Skip to main content

Detrás de la divulgación: la vulnerabilidad Zip Slip

Public Disclosure of Critical Arbitrary File Overwrite Vulnerability Zip Slip

15 de agosto de 2018

0 minutos de lectura

En junio de 2018, el equipo de investigación de Snyk encontró muchas instancias explotables de la vulnerabilidad Zip Slip en distintos ecosistemas, que afectaban a miles de aplicaciones. Una vulnerabilidad de este alcance requiere un proceso de divulgación privada bien planificado, para advertir a las bibliotecas y los proyectos vulnerables sobre su exposición antes de hacerla pública. Pero ¿cómo se encuentra, corrige y divulga una vulnerabilidad así a tantas personas sin que se haga pública? Esta publicación detalla lo que hicimos durante todo el proceso, desde el descubrimiento hasta la divulgación, incluida la creación de pull requests para corregir el problema y mucho más.

Es importante mencionar que Zip Slip no es una vulnerabilidad específica de un paquete o una biblioteca en particular, sino un tipo de vulnerabilidad que permite escribir archivos arbitrarios y es extremadamente común en muchos proyectos. También cabe mencionar que Zip Slip no es una vulnerabilidad nueva en sí: este tipo de vulnerabilidad existe desde hace muchos años, incluso décadas. Sin embargo, dada su prevalencia y la cantidad de ejemplos vulnerables que encontró nuestro equipo de seguridad, nos pareció adecuado darle un nombre, como hicimos con la vulnerabilidad Zip Bomb.

El comienzo

¡Qué mejor lugar para empezar que el principio! A principios de 2018, como parte de nuestra investigación continua, identificamos un patrón vulnerable en la forma en que los clientes FTP manejan las descargas de carpetas y encontramos una implementación explotable en Apache Hive. Esto demuestra que una vulnerabilidad conocida que afectaba a los clientes FTP en 1990 (y antes) todavía existe en muchas bibliotecas de clientes FTP de código abierto escritas en distintos lenguajes de programación. Después seguimos encontrando patrones similares en otras bibliotecas de código abierto de uso extendido.

Decidimos empezar por la extracción de archivos comprimidos. Al extraer archivos de un archivo comprimido, existe un posible vector de ataque que permite el recorrido de directorios. Una vulnerabilidad de recorrido de directorios permite que un atacante acceda a partes del sistema de archivos que están fuera de la carpeta de destino, donde debería limitarse el acceso. Luego, el atacante puede sobrescribir archivos ejecutables e invocarlos de forma remota, o esperar a que el sistema o un usuario los ejecute. Así, puede lograr la ejecución remota de comandos en la máquina de la víctima. La vulnerabilidad también puede causar daños al sobrescribir archivos de configuración u otros recursos sensibles, y se puede explotar tanto en máquinas cliente (de usuarios) como en servidores.

Salida de terminal que muestra entradas del archivo, incluida una ruta de recorrido a /tmp/evil.sh

Cómo encontrar bibliotecas explotables

El equipo empezó a revisar varias muestras de código de bibliotecas populares de código abierto en los ecosistemas de Java, JavaScript y Go. No tuvimos que buscar mucho y, para nuestra sorpresa, encontramos que más de la mitad eran vulnerables. Esto significa que más de la mitad de las bibliotecas iniciales que analizamos no saneaban ni validaban los nombres de archivo presentes en los archivos comprimidos. Si se explota, esto puede permitir sobrescribir archivos arbitrarios. Aquí puedes ver la lista completa.

Desde el principio quedó claro que algunos lenguajes de programación se veían más afectados que otros por esta vulnerabilidad, mientras que en otros prácticamente no existía. Veamos un par de ecosistemas distintos para entender cómo sus diferentes enfoques para ofrecer funciones de administración de archivos comprimidos incidieron en la prevalencia de Zip Slip.

Zip Slip en Java

Por ejemplo, el entorno de ejecución de Java ofrece las clases Zip como parte del lenguaje principal, lo que permite a los desarrolladores escribir código para leer archivos comprimidos y extraer archivos ZIP. Las bibliotecas populares de Java, como Apache Commons-Compress, admiten otros formatos, lo que amplía el alcance del problema. Sin embargo, no existe una API sencilla que realice esta operación en una sola llamada, lo que da lugar a muchas implementaciones diferentes en el ecosistema, la mayoría de las cuales eran vulnerables.

Zip Slip en Python

Python, por otro lado, ofrece la clase zipfile en su entorno de ejecución principal (zipfile.extractall()), y no es vulnerable. Por eso, durante nuestro análisis de repositorios de Python, encontramos de manera constante una implementación segura tras otra.

Cabe señalar que tarfile de Python sí se ve afectado. Esto se debe a que la implementación del entorno de ejecución principal es vulnerable. Si una vulnerabilidad existe en el entorno de ejecución principal de un lenguaje, y no en una biblioteca, puede corregirse automáticamente cuando una aplicación se actualiza a una versión más reciente del lenguaje, sin que se necesiten cambios en la aplicación ni en sus dependencias. Esto suele ocurrir con más frecuencia que la actualización de los desarrolladores a una versión más reciente de una dependencia, a menos, claro, que usen una herramienta como Snyk, que ayuda con eso. (¡Perdón, no pude resistirme a esta promoción descarada!)

¿Quién más es vulnerable?

Pronto quedó claro hasta qué punto estaban afectados algunos de los lenguajes y bibliotecas principales, así que decidimos centrar nuestra atención en los proyectos de código abierto que no eran bibliotecas. Analizamos los proyectos de Java de código abierto más populares alojados en GitHub que contenían código para manipular archivos comprimidos.

Rápidamente notamos que la mayoría de las implementaciones contenían la vulnerabilidad. Era más común en Java, donde vimos que se reutilizaban las mismas implementaciones vulnerables. Esto sugería que esos fragmentos vulnerables se habían tomado de otros proyectos, documentación o comunidades.

StackOverflow: el mercado de las vulnerabilidades

Al analizar el mayor recurso disponible para los desarrolladores que copian y pegan código, pronto quedó claro que nuestra hipótesis era correcta. Encontramos muchas preguntas sobre la mejor manera de extraer archivos de archivos comprimidos mediante código. También descubrimos que casi todas las respuestas en StackOverflow eran vulnerables. Y lo más preocupante: todas las respuestas vulnerables tenían más votos positivos de los que podrías contar. Aquí tienes algunas de nuestras favoritas, junto con un par de comentarios que nos alegraron el día:

Una vez que iniciamos la divulgación privada, nuestro equipo de seguridad siguió investigando y encontró más ejemplos de esta vulnerabilidad. Estas son algunas cifras clave que resumen nuestros hallazgos:

  • 12 bibliotecas vulnerables. Abrimos 5 pull requests para corregir el problema y se integraron.

  • 5 bibliotecas sin una API de alto nivel.

  • Miles de aplicaciones con la implementación vulnerable (no necesariamente explotable).

¿Está mal entusiasmarse?

La labor de un investigador de seguridad consiste en encontrar vulnerabilidades, cerrar brechas de seguridad y ayudar a que el mundo del software sea un lugar seguro, donde miles de millones de personas puedan confiar en que las transacciones empresariales esenciales se realicen correctamente a cada segundo, todos los días. Eso no significa que descubrir una vulnerabilidad de seguridad crítica no sea satisfactorio. Los momentos de revelación que vivimos de vez en cuando en cualquier trabajo nos ayudan a mantener la atención y la precisión durante las etapas menos emocionantes. Saber que un hallazgo interesante o una exposición podrían estar a la vuelta de la esquina nos motiva a pasar días, semanas y meses buscando. Encontrar una vulnerabilidad se parece a la euforia que siente un desarrollador cuando por fin encuentra la causa raíz de un error complejo. O cuando rediseña una aplicación para duplicar su rendimiento o triplicar su escalabilidad.

Cuando descubrimos la primera instancia de la vulnerabilidad Zip Slip en un proyecto grande, nos entusiasmamos mucho. Fue nuestro momento de revelación, pero nos sorprendió muchísimo descubrir que todas las demás aplicaciones tenían una implementación vulnerable. Nos dimos cuenta de que esta vulnerabilidad no afectaba solo a unas pocas aplicaciones, sino a muchísimos proyectos de distintos ecosistemas.

Fue muy emocionante e instructivo analizar todos los datos y entender por qué ciertos lenguajes de programación se veían más afectados y cómo se propagaban los fragmentos de código vulnerables por los proyectos de código abierto. También fue una tarea de investigación completamente distinta a la búsqueda de vulnerabilidades. El verdadero trabajo duro empezó con la divulgación y la ayuda a los proyectos para corregir su código vulnerable: encontrar un eslabón débil es relativamente fácil, pero fortalecerlos todos es difícil.

La divulgación

Seguimos el proceso de divulgación responsable y elegimos el 5 de junio como fecha para la divulgación pública. Esto les dio a los responsables de mantenimiento de los proyectos 60 días para corregir los problemas. Como todos los proyectos vulnerables que encontramos eran de código abierto, la actividad de los repositorios, como las confirmaciones y los pull requests, también era pública y visible. Por eso, era importante equilibrar un plazo razonable para corregir los problemas con el riesgo de exponerlos ampliamente al público, lo que pondría en peligro a los proyectos que aún no los hubieran corregido.

Nuestro primer paso fue contactar a los responsables de mantenimiento de las bibliotecas más utilizadas que tenían la vulnerabilidad para informarles del problema. En esta primera ronda de correos electrónicos, nos comunicamos con 10 en total. Algunos ni siquiera sabían que la biblioteca que habían creado para uso propio se había convertido en una de las bibliotecas de extracción más populares. De esas 10 bibliotecas, 5 responsables de mantenimiento pidieron ayuda para corregir el problema, así que abrimos pull requests para solucionarlo (plexus archiver, mholt/archiver, adm-zip, unzipper y zip4j).

pull request de GitHub que describe una vulnerabilidad Zip Slip que extrae archivos fuera del directorio previsto, con código Java de ejemplo.

Después de comunicarnos con los responsables de mantenimiento de las bibliotecas, contactamos a los proyectos afectados que habían implementado su propia lógica de extracción en vez de usar una biblioteca centralizada. Es probable que ese código se hubiera implementado desde cero o copiado y pegado de documentación, StackOverflow u otros proyectos de código abierto. Cualquiera de estas opciones probablemente habría hecho que se compartiera código vulnerable. Cuando creamos una lista, pronto nos dimos cuenta de que había demasiados proyectos para contactarlos sin correr el riesgo de una filtración pública, ya fuera por las correcciones de los proyectos o por personas irresponsables que compartieran la información sin entender las consecuencias. Al principio nos centramos en los proyectos principales, empezando por Apache, que tenía 15 proyectos con implementaciones vulnerables.

Después de una llamada con Mark J Cox, miembro fundador de Apache Software Foundation y responsable de seguridad de Apache, creamos una hoja de cálculo colaborativa con todos los proyectos posiblemente afectados para que su equipo los clasificara internamente y determinara cuáles eran explotables. Tanto si eran explotables como si no, corregir la implementación vulnerable sigue siendo una buena práctica, y casi todos lo hicieron, debido al riesgo de que se usara en el futuro o se copiara y pegara en otros proyectos. Se determinó que Apache Hadoop, Storm, Hive, Maven y Ant estaban afectados; al momento de la divulgación pública se crearon CVE públicas (CVE-2018-8008, CVE-2018-8009), además de un anuncio de Maven Zip Slip en el sitio de Apache. Fue excelente trabajar con Mark: colaboró muchísimo y nos ayudó a descubrir, corregir y comunicar el problema a cada uno de los proyectos de Apache afectados.

También nos comunicamos con Pivotal (su integración de zip se corrigió en los dos días posteriores a la divulgación), Oracle, Google, OWASP Dependency-Check (se corrigió al día siguiente de la divulgación) y muchos otros.

Por último, queríamos informar de forma privada a todos los demás proyectos afectados. Como eran demasiados proyectos para que un solo equipo los probara y clasificara manualmente, decidimos automatizar el proceso: avisamos a los encargados del mantenimiento sobre el posible riesgo para que comprobaran por su cuenta si su proyecto era realmente vulnerable. Por supuesto, esta divulgación masiva a mayor escala también conlleva el riesgo de que el público se entere. Uno de los proyectos que no era vulnerable publicó el caso en Twitter, por lo que tuvimos que conversar en privado para que retiraran la publicación.

Más allá de la divulgación pública

Cuando el problema se hizo público, publicamos una página informativa con ejemplos vulnerables, soluciones sugeridas y más. Creamos un repositorio colaborativo en GitHub para que la comunidad pudiera saber qué bibliotecas y proyectos estaban afectados y, además, contribuir agregando nuevas bibliotecas y proyectos que no habíamos incluido. Durante el último mes se agregaron varias bibliotecas y proyectos, como closure, sharpziplib y quazip, entre otros.

Si quieres saber más sobre la divulgación de Zip Slip, recibir más consejos sobre divulgación o pedirle a Snyk ayuda con una divulgación privada, escribe a security@snyk.io. Con gusto te ayudaremos a hacer que el código abierto sea más seguro, un commit a la vez.

Comienza con Capture the Flag

Aprende a resolver desafíos de Capture the Flag con nuestro taller virtual 101 a pedido.