SharkCagey / SharkCage

1 stars 3 forks source link

Starting CageManager with SeCreateTokenPrivilege #68

Closed bencikpeter closed 6 years ago

bencikpeter commented 6 years ago

In order for token manipulation to work, the CageManager must be started with a token that has a SeCreateTokenPrivilege

Possible solution is to (from the CageService) locate a process in a system that posseses a desired privilege, get a handle on it, then capture its token and start CageManager with such token

DonatJR commented 6 years ago

Our service is started as LocalSystem, according to MSDN this should already give it the SE_CREATE_TOKEN_NAME privilege. It might just be a matter of enabling it: https://docs.microsoft.com/en-us/windows/desktop/secauthz/enabling-and-disabling-privileges-in-c--

bencikpeter commented 6 years ago

I am sorry to say that, but this is not right. I´ve already battled this problem when implementing the token manipulation library and came across this MSDN post and I am not sure if it is outdated or are we accessing a restricted LocalSystem accout but the privilege is not there. My personal working theory is that whatever system routine is starting our service, it is running CreateRestrictedToken on token we then get.

I´ve explicitly checked for the privilege by starting command line in LocalSystem context.

Output from my system is down below and as you can see, there is no SeCreateTokenPrivilege present.

C:\Windows\system32>whoami
nt authority\system

C:\Windows\system32>whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                            Description                                                        State
========================================= ================================================================== ========
SeAssignPrimaryTokenPrivilege             Replace a process level token                                      Disabled
SeLockMemoryPrivilege                     Lock pages in memory                                               Enabled
SeIncreaseQuotaPrivilege                  Adjust memory quotas for a process                                 Disabled
SeTcbPrivilege                            Act as part of the operating system                                Enabled
SeSecurityPrivilege                       Manage auditing and security log                                   Disabled
SeTakeOwnershipPrivilege                  Take ownership of files or other objects                           Disabled
SeLoadDriverPrivilege                     Load and unload device drivers                                     Disabled
SeSystemProfilePrivilege                  Profile system performance                                         Enabled
SeSystemtimePrivilege                     Change the system time                                             Disabled
SeProfileSingleProcessPrivilege           Profile single process                                             Enabled
SeIncreaseBasePriorityPrivilege           Increase scheduling priority                                       Enabled
SeCreatePagefilePrivilege                 Create a pagefile                                                  Enabled
SeCreatePermanentPrivilege                Create permanent shared objects                                    Enabled
SeBackupPrivilege                         Back up files and directories                                      Disabled
SeRestorePrivilege                        Restore files and directories                                      Disabled
SeShutdownPrivilege                       Shut down the system                                               Disabled
SeDebugPrivilege                          Debug programs                                                     Enabled
SeAuditPrivilege                          Generate security audits                                           Enabled
SeSystemEnvironmentPrivilege              Modify firmware environment values                                 Disabled
SeChangeNotifyPrivilege                   Bypass traverse checking                                           Enabled
SeUndockPrivilege                         Remove computer from docking station                               Disabled
SeManageVolumePrivilege                   Perform volume maintenance tasks                                   Disabled
SeImpersonatePrivilege                    Impersonate a client after authentication                          Enabled
SeCreateGlobalPrivilege                   Create global objects                                              Enabled
SeIncreaseWorkingSetPrivilege             Increase a process working set                                     Enabled
SeTimeZonePrivilege                       Change the time zone                                               Enabled
SeCreateSymbolicLinkPrivilege             Create symbolic links                                              Enabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled

You can perform this check on your computer using PSTools, maybe my system is just messed up.

Startup a command line as an administrator, navigate to PSTools folder and run this, tu start command line as NT AUTHORITY\SYSTEM

psexec.exe -i -s %SystemRoot%\system32\cmd.exe

and then to display privileges available, run

whoami /priv

To the matter of enabling, I am already using this code inside the library to enable and disable that privilege,, but it returns The token does not have the specified privilege message when callig inside CageManager so enabling is definitely not the problem here.

bool setPrivilege(
    HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
)
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!LookupPrivilegeValue(
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup
        &luid))        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError());
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL))
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError());
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}

bool changeTokenCreationPrivilege(bool privilegeStatus) {
    //keeping this for future debug purposes
    //will be important if ever implementing token capture for a token having SE_CREATE_TOKEN_NAME included
    /*
    DWORD bufferSize = 0;
    GetUserName(NULL, &bufferSize);
    LPTSTR pUserName = (LPTSTR) new BYTE[bufferSize * sizeof(TCHAR)];
    GetUserName(pUserName, &bufferSize);
    wprintf(L"User account accessed: %s\n", pUserName);
    delete[](BYTE*) pUserName;
    */

    HANDLE currentProcessHandle;
    HANDLE userTokenHandle;
    currentProcessHandle = GetCurrentProcess();
    if (!OpenProcessToken(currentProcessHandle, TOKEN_ALL_ACCESS, &userTokenHandle)) {
        wprintf(L"Error getting token for privilege escalation\n");
        return false;
    }
    return setPrivilege(userTokenHandle, SE_CREATE_TOKEN_NAME, privilegeStatus);
    CloseHandle(userTokenHandle);
}

My temporary solution while developing TokenLibrary was to manually assign that privilege to the "Administrators" group, but this is massively irresponsible.

DonatJR commented 6 years ago

I am sorry to say that, but this is not right. I´ve already battled this problem when implementing the token manipulation library and came across this MSDN post and I am not sure if it is outdated or are we accessing a restricted LocalSystem accout but the privilege is not there. My personal working theory is that whatever system routine is starting our service, it is running CreateRestrictedToken on token we then get.

Didn't mean to step on your toes, I was just curious about the privileges and found the mentioned MSDN article. Had a look at the service privileges and yeah, it's a shame the article is not accurate :/

Just out of curiosity: We do have the SeTcbPrivilege, so we can act as the system. Does this not allow us to just grant ourselves the SeCreateTokenPrivilege? (I know you would most likely already done this if it was possible, but I'm just wondering why this would not work 😅).

bencikpeter commented 6 years ago

Didn't mean to step on your toes, I was just curious about the privileges and found the mentioned MSDN article. Had a look at the service privileges and yeah, it's a shame the article is not accurate :/

Don´t worry, you didn´t step on anything 😉 If I sounded offended in a previous post, it was not intenended to be that 🙂

We do have the SeTcbPrivilege, so we can act as the system. Does this not allow us to just grant ourselves the SeCreateTokenPrivilege?

Here it starts to be funnny. With having SeTcbPrivilege privilege indeed comes the ability to manipulate tokens and access rights. The catch is, that for individual tokens, WINAPI provides (at least to my knowlege) only functions to remove or restrict privileges. Adding privileges is possible, but only for whole accounts, not individual tokens. The only way to assign new privileges to a token I know about, is to construct a token from scratch using NtCreateToken but that needs SeCreateTokenPrivilege to work. And here we eat our own tail, because the privilege we are trying to grant ourselves is exactly SeCreateTokenPrivilege 🐍

What we have privileges for, is to get tokens of other processes. So if we find a process having SeCreateTokenPrivilege we can just start CageManager with that token and voilaa 🎉

DonatJR commented 6 years ago

Here it starts to be funnny. With having SeTcbPrivilege privilege indeed comes the ability to manipulate tokens and access rights. The catch is, that for individual tokens, WINAPI provides (at least to my knowlege) only functions to remove or restrict privileges.

That's too bad. 😞

What we have privileges for, is to get tokens of other processes. So if we find a process having SeCreateTokenPrivilege we can just start CageManager with that token and voilaa 🎉

Hijacking other processes' tokens just feels hackish, but what can we do. 😆 I guess this just comes with the unusual nature of what we are trying to achieve. We can probably be confident that there exists at least one (system) process with an appropriate token?

Cheers for the detailed explanation! 🥂

bencikpeter commented 6 years ago

Hijacking other processes' tokens just feels hackish, but what can we do. 😆

It indeed is hackish 😅 Actually it was not my idea... I discussed this issue with Langweg a month or two ago. What he told me was:

To enable the SeCreateTokenPrivilege, from the service executed as LocalSystem I had to locate a process that possessed a token that had this privilege, get a handle to that process, get a handle to its token, adjust the token privileges (from disabled to enabled), and then use the modified token in a call to ImpersonateLoggedOnUser(), providing the handle to the modified token as the parameter.

The code is contained in the function SDAcquireTCBPrivilege in file SDModifiedTokens.pas. To find a process from which I could re-use its token, I used the function SDFindPIDWithPrivilege in file SDInfoProcesses.pas.

I did not have time to look into those functions yet (and nor am I very entusiastic to dig around in delphi code 😅 ), but it seems that this approach was successfuly realized in the previous delpi run of the project.

We can probably be confident that there exists at least one (system) process with an appropriate token?

From previously referenced (incorrect) MSDN article it seems like that at least Service Control Manager should be possessing such a privilege... I will have a look at that soon and keep y´all updated 😎

langweg commented 6 years ago

Alternative approach that might work:

  1. Create a new user account for the cage service (permanently/on install)
  2. Assign the SeCreateTokenPrivilege to that user account using the local security policy
  3. Add additional necessary privileges that user account
  4. Run the cage service using that user account
bencikpeter commented 6 years ago

@langweg Thank you for the suggestion. In the meantime I´ve already implemented your previous suggestion with aquiring a token of a different process that already has SeCreateTokenPrivilege and it seems to work pretty well so far. And it was not as difficult to implement as I´ve originaly thought.

You can see the implementation at #71. Maybe you can give me some thoughts on the implementation?

bencikpeter commented 6 years ago

Implemented in #71.