1

Scenario: I have a service that can create, start, stop other services and offers this through IPC to user processes.

How can I check in my service if the calling process has permissions to access the SCM?

So on a more abstract level I have some securable object, in this case the SCM but it can be really anything an other process a thread, a file, folder or reg key, etc... And I have some user process that may or may not have the permissions to access that resource. How can I in a 3rd party process determine if said user process has access to a given securable object?

DavidXanatos
  • 119
  • 1
  • 9
  • You'll want to enumerate the target process' tokens: https://learn.microsoft.com/en-us/windows/win32/secauthz/access-tokens and then use `GetTokenInformation` to see what privileges each token grants. – Dai Jul 01 '20 at 20:21
  • that gives me a list of users and groups and the respective granted or blocked access, then I would have to enum the permissions on the securable object and compare them "by hand". Isn't there an easier way to do that some function call that takes the token and the object and the access mask and returns true/false – DavidXanatos Jul 01 '20 at 20:22
  • I mean i could always impersonate the user process and try to open the object myself and check if it failed or succeeded but that's not so pretty, i would hope there is a more elegant way to do that – DavidXanatos Jul 01 '20 at 20:24
  • 2
    If you want to limit yourself to the permissions of your client, then impersonating the client is the standard solution. – Raymond Chen Jul 01 '20 at 20:31

1 Answers1

0

okay I have it :D that seams to do what I need it to, its based on http://blog.aaronballman.com/2011/08/how-to-check-access-rights/

bool CanAccessSCM(HANDLE idProcess)
{
    bool bRet = false;

    DWORD genericAccessRights = SC_MANAGER_ALL_ACCESS;
    SC_HANDLE scHandle = OpenSCManager(NULL, NULL, READ_CONTROL);
    if (scHandle != NULL) {
        PSECURITY_DESCRIPTOR securityDescriptor;
        if (NT_SUCCESS(GetSecurityInfo(scHandle, SE_SERVICE, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
            , NULL, NULL, NULL, NULL, &securityDescriptor))) {
            HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)(ULONG_PTR)idProcess);
            if (hProcess != NULL) {
                HANDLE hToken = NULL;
                if (OpenProcessToken(hProcess, TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &hToken)) {
                    HANDLE hImpersonatedToken = NULL;
                    if (DuplicateToken(hToken, SecurityImpersonation, &hImpersonatedToken)) {
                        GENERIC_MAPPING mapping = { 0xFFFFFFFF };
                        PRIVILEGE_SET privileges = { 0 };
                        DWORD grantedAccess = 0, privilegesLength = sizeof(privileges);
                        BOOL result = FALSE;
                        /*
                        mapping.GenericRead = FILE_GENERIC_READ;
                        mapping.GenericWrite = FILE_GENERIC_WRITE;
                        mapping.GenericExecute = FILE_GENERIC_EXECUTE;
                        mapping.GenericAll = FILE_ALL_ACCESS;
                        ::MapGenericMask( &genericAccessRights, &mapping );*/
                        if (::AccessCheck(securityDescriptor, hToken, genericAccessRights,
                            &mapping, &privileges, &privilegesLength, &grantedAccess, &result)) {
                            bRet = (result == TRUE);
                        }
                        CloseHandle(hImpersonatedToken);
                    }
                    CloseHandle(hToken);
                }
                CloseHandle(hProcess);
            }
            LocalFree(securityDescriptor);
        }
        CloseHandle(scHandle);
    }

    return bRet;
}
´´´
DavidXanatos
  • 119
  • 1
  • 9
  • at first which ipc you use. many have built-in impersonation api, like `RpcImpersonateClient`, `ImpersonateNamedPipeClient`.. if you use some another way but know client_id of client - you need try first open thread (usually) than (if fail for thread) process token, duplicate for get impersonation token (in case you open process token) and set this token for thread (`SetThreadToken`, or use `ImpersonateLoggedOnUser` - it duplicate token internal, if need, after query it). and do operation with this token, but not check – RbMm Jul 01 '20 at 21:53
  • 1
    The commented generic file rights are a needless distraction when reading the code and should be removed. The rights for the SCM and services are defined [here](https://learn.microsoft.com/en-us/windows/win32/services/service-security-and-access-rights). The `GenericMapping` argument is used for `GenericAll`, to satisfy checking `MAXIMUM_ALLOWED` if an object has no security, but that's unusual for most secured objects other than files. – Eryk Sun Jul 02 '20 at 01:10
  • Set the desired access to `MAXIMUM_ALLOWED` -- plus `ACCESS_SYSTEM_SECURITY` and `WRITE_OWNER` if you want the check to include checking for SeSecurityPrivilege and SeTakeOwnershipPrivilege, respectively. That said, it's better to simply impersonate and try than to use `AccessCheck`. – Eryk Sun Jul 02 '20 at 01:11