2017-11-22 93 views
9

Mã mẫu của tôi hoạt động tốt trên mọi hệ điều hành Windows mà tôi đã có thể kiểm tra, ngoại trừ Windows XP.Lỗi OpenProcessToken với Access Denied (5) trên Windows XP

Khi tôi chạy điều này trên Windows XP với tư cách Quản trị viên, tôi được cung cấp Quyền truy cập bị từ chối (5) khi gọi OpenProcessToken.

Có sự khác biệt nào mà tôi không biết?

#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 [[email protected]] [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); 
} 
+1

PROCESS_QUERY_LIMITED_INFORMATION không tồn tại trên XP vì vậy nó nên thậm chí không nhận được rằng đến nay. – Anders

+0

Bạn chính xác; đã cập nhật nguyên mẫu ... nhưng vẫn nhận được cùng một lỗi _Access bị từ chối_. – wulfgarpro

+0

bạn có chắc chắn rằng sau khi quá trình mở với 'PROCESS_QUERY_INFORMATION' trên xp bạn vẫn có quyền truy cập bị từ chối không? không thể – RbMm

Trả lời

4

vào quá trình XP mà chạy theo LocalSystem (S-1-5-18) có tới DACL trên mã thông báo:

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] 

này có nghĩa là SYSTEM có đầy đủ quyền truy cập TOKEN_ALL_ACCESS (000F01FF) và người dùng từ nhóm Quản trị viên (S-1-5-32-544) có READ_DACL|TOKEN_QUERY (00020008) truy cập

quá trình Mà chạy theo bất kỳ một tài khoản khác có tiếp theo DACL trên Mã:

A 00 000F01FF S-1-5-18 'SYSTEM' 
A 00 000F01FF <UserSid> 
Owner: <UserSid> 

nơi UserSid một số duy nhất (không nhóm!) Sid. nói cho các dịch vụ chạy không dưới LocalSystem nó trông giống như S-1-5-80- .., cho người dùng - S-1-5-21- .. điều này có nghĩa là dacl này cấp toàn quyền truy cập vào 'SYSTEM'bê tông người dùng. nhưng không cấp quyền truy cập vào nhóm Quản trị viên (S-1-5-32-544). để bạn có thể mở bất kỳ mã thông báo quá trình nào chạy dưới cùng một người dùng. nhưng nếu bạn cố gắng mở toke quá trình, mà chạy dưới một người dùng khác (Sid khác) bạn không có bất kỳ quyền truy cập vào nó và có quyền truy cập bị từ chối. bạn thậm chí không thể đọc nó dacl (bạn không phải chủ sở hữu và không có READ_CONTROL).

trong mã bạn thử mở mã thông báo từ một quy trình người dùng khác (sử dụng LogonUser). trong mã thông báo dacl này - không có người dùng của bạn sid hoặc Quản trị viên sid. và kết quả là quyền truy cập bị từ chối

tuy nhiên nếu bạn có đặc quyền sở hữu - trước tiên bạn có thể mở mã thông báo WRITE_OWNER và đặt làm chủ sở hữu, sau khi mở nó với WRITE_DAC (chủ sở hữu có quyền truy cập này) và thay đổi dacl. hoặc, nếu bạn có sự cố gỡ rối, bạn có thể mạo danh luồng hệ thống, bằng cách sử dụng NtImpersonateThread và có toàn quyền truy cập vào mã thông báo.

đang 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(); 

một số kết quả từ 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] 
+0

Rất hữu ích, tôi sẽ xác nhận. – wulfgarpro

+0

@wulfgarpro, hãy đăng mã cuối cùng bạn đã sử dụng và thêm mã đó vào câu trả lời này. Nó sẽ dễ dàng hơn để tham khảo trong tương lai –

+1

@TarunLalwani - tôi thêm mã util cho các thẻ người dùng đổ trong hệ thống. nó đủ lớn và được sử dụng ntapi, nhưng pefect làm việc từ xp để win10 – RbMm

Các vấn đề liên quan