3

I followed Frank K.'s proposed solution for launching a normal user process from an elevated user process. I have however some difficulties on getting the proposed solution working (Win 7 x64 Professional; the "normal user" process is launched from a domain account having administrative rights). The process creation code looks like this:

HANDLE processHandle = getProcessHandle("explorer.exe");

if (OpenProcessToken(processHandle, MAXIMUM_ALLOWED, &hToken))
{
    if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
        SecurityImpersonation, TokenPrimary, &hNewToken))
    {
    LPWSTR pointer = const_cast<LPWSTR>(commandLine.c_str());
    bRet = CreateProcessWithTokenW(hNewToken,
      0, // logon flags
      0, // application name
      pointer, // command-line
      0, // creation flags
      NULL, // environment - inherit from parent
      NULL, // current directory
      &StartupInfo,
      &ProcInfo);
   ...
    }
}

Now the process gets created after the CreateProcessWithTokenW, but my method for checking if the process has administrative rights (see below) says the process has admin rights (as well as ProcessExplorer, which lists in the process properties Security tab: Group: BUILTIN\Administrators --> Flags: Owner).

 BOOL hasAdministratorRights()
 {
  SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  PSID AdministratorsGroup;
  BOOL b = AllocateAndInitializeSid(
    &NtAuthority,
    2,
    SECURITY_BUILTIN_DOMAIN_RID,
    DOMAIN_ALIAS_RID_ADMINS,
    0, 0, 0, 0, 0, 0,
    &AdministratorsGroup);

  if (b)
  {
    if (!CheckTokenMembership(NULL, AdministratorsGroup, &b))
    {
      b = FALSE;
    }
    FreeSid(AdministratorsGroup);
  }
  return b;
 }

Note: if I am calling hasAdministratorRights() above in a process/app started through runAs Windows command (and a given existing local "user" account), it will return false (so it confirms that the process has user rights only, which is what I was expecting). But it is returning true when called in the process created with CreateProcessWithTokenW() above.

Any ideas what I might be doing wrong and why my user process will not get created correctly using CreateProcessWithTokenW?

In Frank K.'s proposed solution, are there differences in behavior of CreateProcessWithTokenW() (and the other APIs) when calling them from a local admin account or from a domain account with admin privileges?

Best regards, Marius

marius.de
  • 107
  • 1
  • 7
  • Is the current (logged-in) user already running elevated? I've not tried it, but Frank's post suggests that you will run the new process as the same user as `explorer.exe` is running. Does `explorer.exe` have Admin rights also? In which case you've duplicated the token for an already-elevated process. No idea if that's the case, just ideas for you to check. – icabod Jun 06 '14 at 12:00
  • Thanks for you suggestion! Indeed, explorer.exe is part of the administrators group. Than the next question would be: what application to use for retrieving a "user" security token? Any ideas? – marius.de Jun 06 '14 at 12:13
  • No idea, but you could have a look at [this SO question](http://stackoverflow.com/q/16099787/218597), where someone is trying to remove Administrative rights from a process, which is similar to what you're trying to do. – icabod Jun 06 '14 at 12:30
  • Thanks, CreateRestrictedToken() seems to be something promising. I will give it a try (but in a week, as I'll be in vacation and will have internet access only). I am however still open to any other suggestions on what is wrong with my implementation of Frank's approach. – marius.de Jun 06 '14 at 12:58
  • The explorer process shouldn't be elevated. It sounds to me as if UAC is disabled on the machine in question; have you checked? – Harry Johnston Jun 07 '14 at 03:58
  • Harry, thank you very much for your suggestion and please apologize my late reply. Your suggestion was right: UAC was disabled. So as soon as UAC was enabled, the newly created process had user rights, as expected. Please re-post your comment as an answer to my original question and I'll gladly mark it as an answer for my question. Kind regards – marius.de Jun 25 '14 at 06:04
  • Beware of a potential C++ UB in the code: `commandLine.c_str()` may return a temporary object which can be destroyed before another C++ expression. `CreateProcess` clearly states that the command line pointer must be a writeable string, so the buffer must be allocated somewhere and live before the call to the `CreateProcess` is returned. – Andry Mar 18 '22 at 11:55

1 Answers1

1

The problem was that UAC was disabled on the machine in question, so no split token was created and the Explorer process had full administrator privilege.

In principle, you could work around this using CreateRestrictedToken(), but if UAC is disabled you should probably assume that this was deliberate, which would usually make the default behaviour, i.e., giving the new process admin privilege, the most sensible choice.

If you need to confirm that the reason a particular token has administrative privilege is because UAC is disabled (including the case where the user is the local Administrator account) you can use GetTokenInformation() with the TokenLinkedToken option.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158