Ошибка OpenProcessToken с отказом в доступе (5) В Windows XP
мой код прототипа отлично работает на каждой ОС Windows, которую я смог протестировать, кроме Windows XP.
когда я запускаю это в Windows XP как администратор, мне дают Доступ запрещен (5) при вызове OpenProcessToken.
есть ли какая-то разница, о которой я не знаю?
#include "stdafx.h"
#include <Windows.h>
#include <userenv.h>
#pragma comment(lib, "userenv")
void DisplayError(LPWSTR pszAPI)
{
LPVOID lpvMessageBuffer;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpvMessageBuffer, 0, NULL);
wprintf(L"ERROR: API = %s.n", pszAPI);
wprintf(L" error code = %d.n", GetLastError());
wprintf(L" message = %s.n", (LPWSTR)lpvMessageBuffer);
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
void SetDebugPrivileges()
{
void* tokenHandle;
TOKEN_PRIVILEGES privilegeToken;
LookupPrivilegeValue(0, SE_DEBUG_NAME, &privilegeToken.Privileges[0].Luid);
privilegeToken.PrivilegeCount = 1;
privilegeToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle);
AdjustTokenPrivileges(tokenHandle, 0, &privilegeToken, sizeof(TOKEN_PRIVILEGES), 0, 0);
CloseHandle(tokenHandle);
}
void wmain(int argc, WCHAR *argv[])
{
DWORD dwSize;
HANDLE hToken;
LPVOID lpvEnv;
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
WCHAR szUserProfile[256] = L"";
si.cb = sizeof(STARTUPINFO);
if (argc != 4)
{
wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
wprintf(L"nn");
return;
}
if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
DisplayError(L"LogonUser");
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
DisplayError(L"CreateEnvironmentBlock");
dwSize = sizeof(szUserProfile) / sizeof(WCHAR);
if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
DisplayError(L"GetUserProfileDirectory");
if (!CreateProcessWithLogonW(argv[1], NULL, argv[2],
LOGON_WITH_PROFILE, NULL, argv[3],
CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
&si, &pi))
DisplayError(L"CreateProcessWithLogonW");
if (!DestroyEnvironmentBlock(lpvEnv))
DisplayError(L"DestroyEnvironmentBlock");
//Sleep(5000);
SetDebugPrivileges();
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pi.dwProcessId);
if(process == NULL)
DisplayError(L"OpenProcess");
// Not working on Windows XP
HANDLE token;
if(!OpenProcessToken(process, TOKEN_QUERY, &token))
DisplayError(L"OpenProcessToken");
CloseHandle(token);
CloseHandle(process);
CloseHandle(hToken);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
1 ответов
на XP процессы, которые работают под LocalSystem
(S-1-5-18) имеют следующий список DACL на знак:
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 00020008 S-1-5-32-544 'Administrators'
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
это означает, что SYSTEM
полный доступ TOKEN_ALL_ACCESS
(000F01FF
) и пользователи из группы Admin (S-1-5-32-544
) у READ_DACL|TOKEN_QUERY
(00020008
) к
процессы, которые запускаются под любой другой учетной записью иметь следующее список DACL на знак:
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF <UserSid>
Owner: <UserSid>
здесь Пользовательsid некоторые уникальные (не группа!) СИД. скажем, за услуги беги не под LocalSystem похоже S-1-5-80- - ... . для пользователей - S-1-5-21- - ... .
это означает, что этот dacl предоставляет полный доступ к 'SYSTEM'
и б пользователей. но не предоставлять доступ к группе администраторов (S-1-5-32-544
). таким образом, вы можете открыть любой токен процесса, который работает под то же самое пользователей. но если вы попробуете открыть процесс toke, который работает под другим пользователем (другой Sid), у вас нет доступа к нему и Вам отказано в доступе. вы не можете даже прочитать его dacl (вы не владелец и не имеете READ_CONTROL
).
в коде вы пытаетесь открыть токен из другого пользовательского процесса (LogonUser
используется). в этом токене dacl-нет вашего SID пользователя или Sid администраторов. в результате и доступ запрещен
однако, если у вас есть привилегия takeownership-вы можете сначала открыть токен с WRITE_OWNER
и установите себя как владельца, после этого откройте его с WRITE_DAC
(владелец имеет этот доступ) и измените dacl. или, если у вас есть debug provilege, вы можете олицетворите системный поток, используя NtImpersonateThread
и иметь полный доступ к маркеру.
util код:
#ifdef __cplusplus
extern "C" {
#endif
NTSYSCALLAPI
NTSTATUS
NTAPI
NtOpenThread(
_Out_ PHANDLE ThreadHandle,
_In_ ULONG DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ PCLIENT_ID ClientId
);
extern "C"
NTSYSCALLAPI
NTSTATUS
NTAPI
NtImpersonateThread(
_In_ HANDLE ServerThreadHandle,
_In_ HANDLE ClientThreadHandle,
_In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos
);
#ifdef __cplusplus
}
#endif
ULONG gOsVersion;
volatile UCHAR guz;
OBJECT_ATTRIBUTES zoa = { sizeof(zoa) };
void GetVersionEx()
{
RTL_OSVERSIONINFOW VersionInformation;
RtlGetVersion(&VersionInformation);
gOsVersion = (VersionInformation.dwMajorVersion << 8) + VersionInformation.dwMinorVersion;
}
PCSTR GetSidNameUseName(::SID_NAME_USE snu)
{
switch (snu)
{
case SidTypeUser: return "User";
case SidTypeGroup: return "Group";
case SidTypeDomain: return "Domain";
case SidTypeAlias: return "Alias";
case SidTypeWellKnownGroup: return "WellKnownGroup";
case SidTypeDeletedAccount: return "DeletedAccount";
case SidTypeInvalid: return "Invalid";
case SidTypeUnknown: return "Unknown";
case SidTypeComputer: return "Computer";
case SidTypeLabel: return "Label";
case SidTypeLogonSession: return "LogonSession";
}
return "?";
}
#define MAX_DOMAIN_NAME_LEN 128
void DumpAcl(PACL acl, PCSTR caption)
{
DbgPrint(caption);
if (!acl)
{
DbgPrint("NULL\n");
return;
}
USHORT AceCount = acl->AceCount;
if (!AceCount)
{
DbgPrint("empty\n");
return;
}
DbgPrint("T FL AcessMsK Sid\n");
union {
PVOID pv;
PBYTE pb;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paaa;
};
pv = acl + 1;
char sz[16], sz2[16];
do
{
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
break;
default:
DbgPrint("AceType=%u\n", pah->AceType);
continue;
}
UNICODE_STRING us;
if (0 <= RtlConvertSidToUnicodeString(&us, (PSID)&paaa->SidStart, TRUE))
{
WCHAR name[256], DomainName[MAX_DOMAIN_NAME_LEN];
ULONG cch = RTL_NUMBER_OF(name);
::SID_NAME_USE snu;
DWORD cchReferencedDomainName = MAX_DOMAIN_NAME_LEN;
if (!LookupAccountSidW(0, (PSID)&paaa->SidStart, name, &cch, DomainName, &cchReferencedDomainName, &snu))
{
name[0]=0;
}
ACCESS_MASK Mask = paaa->Mask;
sprintf(sz2, "%08X", Mask);
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
sz[0] = 'A', sz[1] = 0;
break;
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
sz[0] = 'D', sz[1] = 0;
break;
case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
sz[0] = 'L', sz[1] = 0;
sz2[0] = Mask & SYSTEM_MANDATORY_LABEL_NO_READ_UP ? 'R' : ' ';
sz2[1] = Mask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP ? 'W' : ' ';
sz2[2] = Mask & SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP ? 'E' : ' ';
sz2[3] = 0;
break;
default: __assume(false);
}
DbgPrint("%s %02X %s %wZ '%S'\n", sz, paaa->Header.AceFlags, sz2, &us, name);
RtlFreeUnicodeString(&us);
}
} while (pb += pah->AceSize, --AceCount);
}
void Dump(HANDLE hToken)
{
ULONG cb = 0, rcb = 128;
PVOID stack = alloca(guz);
union {
PVOID buf;
PSECURITY_DESCRIPTOR psd;
PTOKEN_USER ptu;
};
UNICODE_STRING us;
::SID_NAME_USE snu;
WCHAR name[256], DomainName[MAX_DOMAIN_NAME_LEN];
ULONG cch, cchReferencedDomainName;
NTSTATUS status;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQueryInformationToken(hToken, TokenUser, buf, cb, &rcb)))
{
if (0 <= RtlConvertSidToUnicodeString(&us, ptu->User.Sid, TRUE))
{
cch = RTL_NUMBER_OF(name);
cchReferencedDomainName = RTL_NUMBER_OF(DomainName);
if (!LookupAccountSidW(NULL, ptu->User.Sid, name, &cch, DomainName, &cchReferencedDomainName, &snu))
{
*name = 0;
*DomainName = 0;
}
DbgPrint("User: %wZ '%S' @ '%S' [%s]\r\n", &us, name, DomainName, GetSidNameUseName(snu));
RtlFreeUnicodeString(&us);
}
break;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
if (0 > status)
{
DbgPrint("TokenUser=%x\n", status);
}
SECURITY_INFORMATION SecurityInformation = gOsVersion < _WIN32_WINNT_VISTA
? OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION
: OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQuerySecurityObject(hToken, SecurityInformation, psd, cb, &rcb)))
{
PACL Acl;
BOOLEAN bPresent, bDefault;
if (0 <= RtlGetDaclSecurityDescriptor(psd, &bPresent, &Acl, &bDefault))
{
DumpAcl(bPresent ? Acl : 0, "DACL:\n");
}
if (0 <= RtlGetSaclSecurityDescriptor(psd, &bPresent, &Acl, &bDefault))
{
DumpAcl(bPresent ? Acl : 0, "LABEL:\n");
}
PSID Owner;
if (0 <= RtlGetOwnerSecurityDescriptor(psd, &Owner, &bDefault) && Owner)
{
if (0 <= RtlConvertSidToUnicodeString(&us, Owner, TRUE))
{
cch = RTL_NUMBER_OF(name);
cchReferencedDomainName = RTL_NUMBER_OF(DomainName);
if (!LookupAccountSidW(NULL, Owner, name, &cch, DomainName, &cchReferencedDomainName, &snu))
{
*name = 0;
*DomainName = 0;
}
DbgPrint("Owner: %wZ '%S' @ '%S' [%s]\r\n", &us, name, DomainName, GetSidNameUseName(snu));
RtlFreeUnicodeString(&us);
}
}
}
} while (status == STATUS_BUFFER_TOO_SMALL);
if (0 > status)
{
DbgPrint("QuerySecurityObject=%x\n", status);
}
}
void Dump(ACCESS_MASK DesiredAccess, PSYSTEM_PROCESS_INFORMATION pspi)
{
HANDLE hProcess, hToken;
CLIENT_ID cid = { pspi->UniqueProcessId };
DbgPrint("==============\n%p %wZ\n", cid.UniqueProcess, &pspi->ImageName);
NTSTATUS status = NtOpenProcess(&hProcess, DesiredAccess, &zoa, &cid);
if (0 > status)
{
DbgPrint("OpenProcess=%x\n", status);
return;
}
status = NtOpenProcessToken(hProcess, READ_CONTROL|TOKEN_QUERY, &hToken);
NtClose(hProcess);
if (0 > status)
{
DbgPrint("OpenProcessToken=%x\n", status);
}
else
{
Dump(hToken);
NtClose(hToken);
}
}
void DumpProcessAndTokens(PVOID buf)
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
ACCESS_MASK DesiredAccess = gOsVersion < _WIN32_WINNT_VISTA
? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION;
do
{
pb += NextEntryOffset;
if (pspi->UniqueProcessId)
{
Dump(DesiredAccess, pspi);
}
} while (NextEntryOffset = pspi->NextEntryOffset);
}
NTSTATUS GetSystemToken(PCLIENT_ID ClientId)
{
HANDLE hThread;
NTSTATUS status = NtOpenThread(&hThread, THREAD_DIRECT_IMPERSONATION, &zoa, ClientId);
if (0 <= status)
{
static SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE
};
if (0 <= (status = NtImpersonateThread(NtCurrentThread(), hThread, &sqos)))
{
HANDLE hToken;
if (0 <= (status = NtOpenThreadTokenEx(NtCurrentThread(), TOKEN_QUERY,FALSE, 0, &hToken)))
{
ULONG cb = 0, rcb = 32;
PVOID stack = alloca(guz);
union {
PVOID buf;
PTOKEN_USER ptu;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQueryInformationToken(hToken, TokenUser, buf, cb, &rcb)))
{
static _SID LocalSystem = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } };
if (!RtlEqualSid(&LocalSystem, ptu->User.Sid))
{
RevertToSelf();
status = STATUS_SERVER_SID_MISMATCH;
}
break;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
NtClose(hToken);
}
}
NtClose(hThread);
}
return status;
}
NTSTATUS ImpersonateLocalSystem(PVOID buf)
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
if (pspi->UniqueProcessId && pspi->NumberOfThreads)
{
if (0 <= GetSystemToken(&pspi->TH->ClientId))
{
return STATUS_SUCCESS;
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return STATUS_UNSUCCESSFUL;
}
void DumpProcessTokens()
{
BOOLEAN b;
NTSTATUS status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
if (0 > status)
{
return ;
}
ULONG cb = 0x8000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PVOID buf = new UCHAR[cb])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
if (0 <= ImpersonateLocalSystem(buf))
{
DumpProcessAndTokens(buf);
RevertToSelf();
}
}
delete [] buf;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
}
GetVersionEx();
DumpProcessTokens();
некоторый результат от xp:
00000004 System
User: S-1-5-18 'SYSTEM' @ 'NT AUTHORITY' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
LABEL:
NULL
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
==============
0000021C smss.exe
User: S-1-5-18 'SYSTEM' @ 'NT AUTHORITY' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 00020008 S-1-5-32-544 'Administrators'
LABEL:
NULL
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
==============
000003B0 svchost.exe
User: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-80-979556362-403687129-3954533659-2335141334-1547273080 ''
LABEL:
NULL
Owner: S-1-5-80-979556362-403687129-3954533659-2335141334-1547273080 '' @ '' [WellKnownGroup]
==============
0000047C svchost.exe
User: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-20 'NETWORK SERVICE'
LABEL:
NULL
Owner: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
==============
000004C4 svchost.exe
User: S-1-5-19 'LOCAL SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-19 'LOCAL SERVICE'
LABEL:
NULL
Owner: S-1-5-19 'LOCAL SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
==============
000005EC explorer.exe
User: S-1-5-21-839522115-2025429265-725345543-500 'Administrator' @ '*' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-21-839522115-2025429265-725345543-500 'Administrator'
A 00 000F01FF S-1-5-18 'SYSTEM'
LABEL:
NULL
Owner: S-1-5-21-839522115-2025429265-725345543-500 'Administrator' @ '*' [User]