Token impersonation

Token impersonation

TL;DR: If you sit in a service account context that holds SeImpersonatePrivilege (IIS, MSSQL, scheduled tasks), trick a SYSTEM-owned process into authenticating to a socket you control, capture its token via ImpersonateNamedPipeClient or RpcImpersonateClient, and spawn a process as SYSTEM with CreateProcessWithTokenW.

What it is

Windows lets a server thread “wear” the security context of a client that has connected to it. The privilege that gates this is SeImpersonatePrivilege, and it is granted by default to LocalService, NetworkService, and any account assigned the “Impersonate a client after authentication” right — which is almost every service account. The Potato family of exploits abuses this by coercing a SYSTEM service to authenticate to an attacker-controlled endpoint, then impersonating that connection. See tokens-and-privileges for the underlying token model.

Preconditions / where it applies

  • Code execution as a service account holding SeImpersonatePrivilege (check with whoami /priv)
  • A SYSTEM service willing to call back to a local endpoint — Spooler (PrintSpoofer), RPC/DCOM (RoguePotato, JuicyPotatoNG, GodPotato), WebClient/WebDAV (PetitPotam-style on a local pipe), CertSrv, etc.
  • Local network reachability between the attacker process and the coerced caller (named pipe or loopback TCP)

Technique

PrintSpoofer (simple, requires Spooler enabled — still useful on workstations):

PrintSpoofer.exe -i -c "cmd /c whoami"
:: → nt authority\system

It calls RpcRemoteFindFirstPrinterChangeNotificationEx against the local Spooler RPC endpoint with a UNC-style path that forces Spooler (SYSTEM) to connect back to an attacker-named pipe; on connect the attacker calls ImpersonateNamedPipeClient and CreateProcessAsUser.

GodPotato (works post-Spooler-disabled, uses RPC SS COM):

GodPotato -cmd "cmd /c whoami"

Generic flow regardless of variant:

  1. Acquire SeImpersonatePrivilege (default in IIS app pool, MSSQL service, etc.).
  2. Stand up a server endpoint (named pipe \\.\pipe\<rand> or TCP loopback).
  3. Trigger a SYSTEM-owned service to authenticate to that endpoint via RPC/DCOM/Spooler coercion.
  4. On the incoming connection call ImpersonateNamedPipeClientOpenThreadTokenDuplicateTokenEx(TokenPrimary)CreateProcessWithTokenW.

Watch out for ERROR_BAD_IMPERSONATION_LEVEL (1346) from DuplicateTokenEx — it means the server thread did not actually carry SeImpersonatePrivilege when the duplication attempt happened, usually because the call ran before ImpersonateNamedPipeClient returned or in a thread whose token had been reverted. Pass SecurityImpersonation (not SecurityDelegation) as the impersonation level for local SYSTEM spawns — SecurityDelegation is only needed if you intend to forward the token over the network and will be rejected for non-network logon types. Enumerate live pipes ahead of time with (Get-ChildItem \\.\pipe\).name so your pipe name does not collide with a legitimate one (Meterpreter’s getsystem historically used predictable names that Sysmon Event 17/18 rules now flag).

The historical timeline matters: RottenPotato/JuicyPotato (DCOM loopback marshalling) → patched 2019 → RoguePotato (OXID resolver redirect) → PrintSpoofer/SeBatchLogonRight bypasses → JuicyPotatoNG, GodPotato, EfsPotato, DCOMPotato. Microsoft hardens specific RPC interfaces each round; a new variant pops within months.

Detection and defence

  • Remove SeImpersonatePrivilege from non-essential service accounts; never grant it to interactive users
  • Disable Print Spooler on servers that do not print
  • Sysmon event 1 with parent IIS/SQL spawning cmd.exe/powershell.exe running as SYSTEM is a strong signal
  • EDRs watch named-pipe-impersonation API sequences and DCOM OXID anomalies
  • Application Whitelisting (WDAC) blocks attacker binaries in the IIS app-pool directories
  • Run services as virtual accounts (NT SERVICE<svc>) or gMSAs and audit Impersonate a client after authentication user-right assignments

References