我的原型代码在我能够testing的每个Windows操作系统上都能正常工作,除了Windows XP。
当我以pipe理员身份在Windows XP上运行此操作时,调用OpenProcessToken时, Access被拒绝(5) 。
有没有我不知道的一些区别?
#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"\n\n"); 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); }
在LocalSystem
( S-1-5-18 )下运行的XP进程在令牌上有下一个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>
其中UserSid有一些独特的(不是group!)sid。 对于不在LocalSystem下运行的服务,它看起来像S-1-5-80- ,对于用户-S-1-5-21- ..这意味着这个dacl授予对'SYSTEM'
和具体用户的完全访问权限。 但不授予对管理员组( S-1-5-32-544
)的任何访问权限。 所以你可以打开任何在同一个用户下运行的进程令牌。 但如果你尝试打开进程toke,在另一个用户(另一个Sid)下运行,你没有任何访问权限,并被拒绝访问。 你甚至不能读它达克(你不是所有者,没有READ_CONTROL
)。
在代码中,您尝试从另一个用户进程打开令牌(使用LogonUser
)。 在这个令牌DACL – 没有你的用户sid或管理员sid。 作为结果和访问被拒绝
但是,如果您拥有所有权特权,则可以先用WRITE_OWNER
打开标记,然后将自己设置为所有者,然后使用WRITE_DAC
(所有者拥有此访问权限)打开标记并更改dacl。 或者,如果您具有调试特权,则可以使用NtImpersonateThread
模拟系统线程,并拥有对令牌的完全访问权限。
实用代码:
#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]