Skip to main content

Snyking In: explotación de una vulnerabilidad de denegación de servicio por expresiones regulares en el paquete ms

Escrito por
Snyking in small

13 de marzo de 2019

0 minutos de lectura

¡Te damos la bienvenida a otra edición de nuestra serie de exploits Snyking In! La vez pasada vimos un exploit de una vulnerabilidad de recorrido de directorios en la biblioteca st. En este episodio veremos la vulnerabilidad de denegación de servicio por expresiones regulares, mostraremos cómo se puede explotar y explicaremos el riesgo potencial que representa para tus datos y sistemas.

También te mostraremos cómo encontrar y corregir este tipo de vulnerabilidad en tu aplicación. Sin más preámbulos, aquí tienes el video del exploit, seguido de más información sobre la vulnerabilidad de denegación de servicio por expresiones regulares.

Snyking In - Regular Expression Denial of Service vulnerability exploit in the ms package

Denegación de servicio por expresiones regulares

La denegación de servicio (DoS) describe una familia de ataques cuyo objetivo es impedir que los usuarios legítimos originales puedan acceder a un sistema. Hay muchos tipos de ataques DoS, desde intentar saturar los canales de red del sistema al generar un gran volumen de tráfico desde muchas máquinas (un ataque distribuido de denegación de servicio, DDoS) hasta enviar solicitudes diseñadas para hacer que un sistema falle o tarde una cantidad desproporcionada de tiempo en procesarlas.

La denegación de servicio por expresiones regulares (ReDoS) es un tipo de ataque de denegación de servicio. Las expresiones regulares son increíblemente potentes, pero no son muy intuitivas y, en última instancia, pueden facilitar que los atacantes dejen tu sitio fuera de servicio.

El reciente informe sobre el estado de la seguridad del código abierto, publicado por Snyk, reveló que las divulgaciones de vulnerabilidades de denegación de servicio por expresiones regulares aumentaron un 143 % solo durante el último año.

Gráfico de líneas titulado «Aumentan las divulgaciones de vulnerabilidades de denegación de servicio por expresiones regulares (ReDoS)», que muestra un aumento de 14 en 2016 a 30 en 2017 y 72 en

Retroceso catastrófico

Veamos la siguiente expresión regular:

regex = /A(B|C+)+D/

Esta expresión regular hace lo siguiente:

  • A La cadena debe comenzar con la letra A

  • (B|C+)+ Después de la letra A, la cadena debe incluir la letra B o una o más apariciones de la letra C (el signo + indica una o más apariciones). El signo + al final de esta sección indica que podemos buscar una o más coincidencias de esta sección.

  • D Por último, nos aseguramos de que esta sección de la cadena termine con una D

La expresión coincidiría con entradas como ABBD, ABCCCCD, ABCBCCCD y ACCCCCD. En la mayoría de los casos, el motor de expresiones regulares encuentra una coincidencia rápidamente:

$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total

$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total

Todo el proceso de probarla con una cadena de 30 caracteres tarda alrededor de 52 ms. Pero, si se proporciona una cadena no válida, la prueba tarda casi dos segundos en completarse: más de diez veces lo que tardó en probar una cadena válida. Esta diferencia tan marcada se debe a la forma en que se evalúan las expresiones regulares.

La mayoría de los motores de expresiones regulares funcionan de manera muy similar (con pequeñas diferencias). El motor encuentra la primera forma posible de aceptar el carácter actual y continúa con el siguiente. Si no logra coincidir con el siguiente carácter, retrocede para ver si había otra forma de procesar el carácter anterior. Si avanza demasiado por un camino sin salida y luego descubre que la cadena no coincide, y si muchos caracteres tienen varias rutas válidas en la expresión regular, la cantidad de pasos de retroceso puede volverse muy grande. Esto se conoce como retroceso catastrófico.

El exploit de ms

El siguiente comando agrega una tarea pendiente a nuestra aplicación de tareas Snyk Goof. El motor de expresiones regulares interpreta la parte in 20 minutes del texto como una representación de tiempo. Por ejemplo, la lógica de negocio de la aplicación podría usar esto para crear recordatorios o alertas.

$ echo 'content=Call mom in 20 minutes' | http --form http://localhost:3001/create -v

Podemos intentar forzar la longitud de la entrada de la tarea pendiente de la siguiente manera. El comando imprime 60000 5s como cantidad de minutos, pero responde muy rápido porque el patrón todavía coincide.

$ echo 'content=Buy milk in '`printf %.0s5 {1..60000}`' minutes' | http --form http://localhost:3001/create -v

Para provocar una denegación de servicio, hay que pasar una cadena que genere una situación de retroceso catastrófico. En parte, esto requiere una cadena de entrada larga, como en el ejemplo anterior, pero también debemos asegurarnos de que el motor de expresiones regulares nunca encuentre una coincidencia con el patrón y, por lo tanto, retroceda por todas las posibilidades antes de fallar. Esto provoca la demora o denegación de servicio que buscamos. Para lograrlo, podemos cambiar el texto minutes de nuestro contenido por minutea, por ejemplo, un patrón con el que el motor de expresiones regulares no encontrará coincidencias. El siguiente comando de entrada provocará una denegación de servicio de unos 10 a 15 segundos. Si pasamos 600000 5s, tendremos que esperar prácticamente todo el día para que el servidor complete la solicitud.

$ echo 'content=Buy milk in '`printf %.0s5 {1..60000}`' minutea' | http --form http://localhost:3001/create -v

Para probar si tu aplicación tiene vulnerabilidades en bibliotecas de terceros, como ms, prueba Snyk gratis.

Empieza con los desafíos de Capture the Flag

Aprende a resolver desafíos de captura la bandera con nuestro taller virtual introductorio a pedido.