Skip to main content

Exploración de la vulnerabilidad de seguridad de contaminación de prototipos en minimist

Escrito por
Headshot of Kirill Efimov

Kirill Efimov

26 de marzo de 2020

0 minutos de lectura

El 11 de marzo de 2020, Snyk publicó una vulnerabilidad de seguridad de contaminación de prototipos de gravedad media (CVE-2020-7598) que afecta al paquete npm minimist. Esto forma parte de una investigación continua del equipo de investigación de seguridad de Snyk, que anteriormente había descubierto vulnerabilidades similares en otras bibliotecas JavaScript destacadas, como lodash y jQuery.

¿Qué es una vulnerabilidad de contaminación de prototipos?

Esta vulnerabilidad de seguridad, que se manifiesta como contaminación de prototipos, permite que los atacantes sobrescriban el prototipo de un objeto de una aplicación JavaScript. Cuando esto sucede, se pueden inyectar propiedades controladas por el atacante en los objetos, lo que puede provocar una denegación de servicio al desencadenar excepciones de JavaScript o alterar el código fuente de la aplicación para forzar la ejecución de la ruta de código inyectada por el atacante.

La investigación actual del equipo de Snyk también descubrió vulnerabilidades de seguridad similares en otros paquetes npm, algunos tan destacados como yargs-parser:

Resultados de búsqueda en la base de datos de vulnerabilidades de Snyk para “minimist”, con vulnerabilidades de inyección de comandos npm y contaminación de prototipos.
vulnerabilidades de contaminación de prototipos descubiertas por el equipo de investigación de seguridad de Snyk: https://snyk.io/vuln?type=npm

El equipo de investigación de seguridad de Snyk sigue las pautas de divulgación responsable y trabajó con quienes mantienen minimist, yargs-parser y otros proyectos para comunicar nuestros hallazgos, validarlos y verificarlos con sus respectivos responsables, quienes confirmaron y coincidieron en que la superficie de ataque era vulnerable.

Queremos agradecer a quienes mantienen estos proyectos por responder rápidamente y publicar las correcciones en poco tiempo, además de adaptar las correcciones de seguridad a versiones anteriores; por ejemplo, la corrección de seguridad de minimist para las versiones anteriores a la 1.0.0 y la corrección de seguridad de yargs-parser para las versiones anteriores a la 13.1.2.

Contaminación de prototipos en analizadores de CLI

Ten en cuenta que en esta publicación no explicaré los conceptos básicos de la contaminación de prototipos: ya hay suficientes artículos sobre el tema. También publicamos en nuestro blog un artículo detallado que ofrece una buena introducción a los conceptos básicos de las vulnerabilidades de contaminación de prototipos.

En esta publicación, en cambio, quiero:

  1. Explicar qué son los analizadores de argumentos de línea de comandos (CLI) y cómo se usan habitualmente en el ecosistema JavaScript actual.

  2. Mostrar cómo las aplicaciones que dependen de este tipo de analizadores pueden ser vulnerables a ataques de contaminación de prototipos, con ejemplos reales de paquetes vulnerables.

  3. Explicar los motivos de la clasificación de gravedad y la evaluación general de la vulnerabilidad de estos problemas.

Es una biblioteca para argumentos de línea de comandos: ¿no es básicamente como atacarse a uno mismo?

Tanto minimist como yargs-parser son bibliotecas JavaScript creadas para analizar los argumentos de aplicaciones Node.js de línea de comandos. Veamos cómo una CLI de Node.js puede provocar una escalada local de privilegios debido a una validación inadecuada de entradas (CWE-20), una vulnerabilidad común con miles de casos y CVE documentados. 

En el siguiente ejemplo, crearemos una utilidad del sistema que permite a usuarios sin privilegios de root reiniciar un servidor. En este ejemplo, usamos minimist con un único propósito: mostrar una pequeña ayuda para la opción de línea de comandos --help.

El siguiente código muestra nuestra pequeña CLI de Node.js, llamada u-reboot:

const argv = require('minimist')(process.argv.slice(2));
const cp = require('child_process');
if (argv.help) {
    console.log("My awesome reboot utility with no root access required");
} else {
    cp.execSync('reboot', {uid: 0});
}

Para distribuir esta magnífica herramienta de una forma más práctica, debemos compilarla como un binario independiente. Podemos usar pkg para hacerlo:

npm install -g pkg
pkg u-reboot.js --target node10-linux-x64

Por último, para que funcione, debemos asignar los permisos adecuados al binario:

chown root u-reboot
chmod 4555 u-reboot

4555 es un permiso de lectura y ejecución para todos los usuarios, además del indicador setuid. Lee más sobre setuid aquí; en pocas palabras, permite ejecutar el binario con los permisos de su propietario (en nuestro caso, el usuario root).

Ahora tenemos una herramienta de línea de comandos llamada u-reboot que cualquier usuario puede ejecutar para reiniciar el servidor o la estación de trabajo, pero no queremos permitir que haga nada más en el servidor.

¿Cómo se puede abusar ahora de una aplicación de línea de comandos como esta? Ten en cuenta que los usuarios tienen pocos privilegios en el servidor y no deberían poder ejecutar otros comandos como root.

Explotación de aplicaciones CLI de Node.js

La vulnerabilidad de seguridad en minimist nos permite contaminar el prototipo de Object. De pronto, u-reboot se vuelve vulnerable a un caso clásico de escalada de privilegios.

printf '#!/bin/shn id' > /tmp/exploit
chmod +x /tmp/exploit
u-reboot --__proto__.shell /tmp/exploit

¿Ves uid=0(root) en el resultado? Ahora podemos ejecutar cualquier comando con credenciales de root al explotar la vulnerabilidad de contaminación de prototipos en minimist, que usa la CLI u-reboot.

El ataque es posible porque child_peorccess.execSync tiene un objeto options con una propiedad opcional shell. Si shell está vacío, execSync usará /bin/sh, según la documentación. Pero si contaminamos todos los objetos con una propiedad shell cuyo valor sea /tmp/exploit, execSync usará nuestro exploit como shell.

Parece una vulnerabilidad local. ¿Por qué dices que tiene un vector de ataque de red?

Esto me recuerda a la vulnerabilidad shellshock, publicada en 2014. En ese caso, se puede engañar al shell Bash para que ejecute código arbitrario inyectado mediante variables de entorno. Parece una vulnerabilidad completamente local (¿quién más puede controlar las variables de entorno?), pero Bash se usa con mucha frecuencia: muchos servicios web lo usan para procesar solicitudes, lo que permite que un atacante ejecute comandos arbitrarios. Te recomiendo leer esta breve explicación si aún no conoces la vulnerabilidad.

¿Esta vulnerabilidad solo permite escalar privilegios? No. Nuestro equipo de investigación examinó distintos casos de uso de minimist y yargs-parser y encontró un par de ejemplos interesantes. No analizaré cada caso en detalle; estos ejemplos muestran que los analizadores de argumentos de CLI no siempre se usan como cabría esperar.

  1. Terminal in React: un componente de React para emular una terminal en un navegador web. Usa minimist para analizar los argumentos de CLI de los comandos. Puedes encontrar más ejemplos de emuladores de terminal.

  2. Los argumentos de los chatbots suelen parecer argumentos de CLI, ¿verdad? Encontramos muchos ejemplos de personas que usan analizadores de argumentos de CLI para ese fin: 1, 2, 3, 4, 5.

  3. apibone: una biblioteca que ofrece interfaces para servicios consultables. Simplemente abstrae los objetos de solicitud y respuesta de las funciones que define. Usa yargs-parser para analizar partes de las consultas HTTP.

Si buscas con atención en los repositorios de código abierto de GitHub, encontrarás más ejemplos con patrones de uso distintos y poco evidentes.

¿Deberían estas aplicaciones evitar usar una biblioteca como minimist, creada para analizar argumentos de CLI, y reutilizarla para crear aplicaciones web y de red? Tal vez. En Snyk, creemos que los analizadores son componentes de código de gran responsabilidad. Por lo general, están al inicio del proceso de manejo de datos e interactúan directamente con las entradas del usuario.

Además, minimist es una biblioteca de análisis de argumentos de propósito general, ya que no está ligada directamente a algo como process.argv de Node.js. Puedes usar minimist con un arreglo de cadenas y las analizará como si fueran argumentos de CLI.

Piénsalo: ¿cuántos problemas han causado los analizadores XML? ¿O el mecanismo de deserialización de Java? Seguramente recuerdas bourne JSON parser, escrito por Eran Hammer después de lidiar con problemas de contaminación de prototipos relacionados con hapi y joi. Bourne JSON parser se creó con un único propósito: proteger contra las propiedades __proto__ en una carga JSON. Puedes leer más en su artículo.

¿Cómo clasificamos la gravedad de esta vulnerabilidad?

Para describir la vulnerabilidad, asignamos el siguiente vector CVSS: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L.

  1. Vector de ataque: red. Encontramos usos de minimist y yargs-parser en varios chatbots y aplicaciones web. Aunque no sea una buena práctica usar estas bibliotecas en esos casos, no podemos ignorar que hay quienes efectivamente las usan.

  2. Complejidad del ataque: alta. Las vulnerabilidades de contaminación de prototipos se convierten en una amenaza real solo si el atacante encuentra un gadget adecuado para ejecutar código de forma remota u otra acción que le permita continuar el ataque. En nuestro ejemplo, la llamada “execSync” cumple la función de ese gadget.

  3. Privilegios requeridos: ninguno. El atacante debe poder enviar una cadena que se interprete como argumentos de CLI. No se requieren privilegios especiales.

  4. Interacción del usuario: ninguna.

  5. Alcance: sin cambios. Creo que estas dos propiedades no requieren más explicación.

  6. Confidencialidad: baja.

  7. Integridad: baja.

  8. Disponibilidad: baja. Estas tres propiedades tienen un nivel bajo por los motivos descritos en el punto 2: las vulnerabilidades de contaminación de prototipos deben evaluarse en el contexto de una aplicación.

Definitivamente, esta vulnerabilidad no tiene una gravedad alta (su puntuación CVSS es 5.6, es decir, media), pero nuestro equipo de investigación ve claramente muchos escenarios de ataque distintos. Además, creemos que la popularidad de las dos bibliotecas mencionadas justifica una divulgación y una corrección adecuadas.

¿Qué debo hacer ahora?

  • Si ya usas Snyk para monitorear tus aplicaciones y lo conectaste a tus repositorios de GitHub o Bitbucket, ya deberías haber recibido un pull request automatizado de Snyk para actualizar tus proyectos a las versiones corregidas de las bibliotecas vulnerables.

  • Si no usas Snyk, puedes agregar tus proyectos. Snyk es gratis para proyectos de código abierto y puedes importar tus proyectos desde tus repositorios de código al panel de Snyk.

Comienza con Capture the Flag

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

Leer más

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.

feature insights context
Blog

Los ataques autónomos ya están aquí. La defensa debe estar a su altura.

Los atacantes autónomos están reduciendo el tiempo disponible para defenderse. Descubre cómo el descubrimiento, la corrección, la validación y la prevención continuos pueden ayudar a los equipos de seguridad a seguirles el ritmo.

Blog

Tu backlog de vulnerabilidades ya no es deuda técnica: es una superficie de ataque

Un backlog de vulnerabilidades en crecimiento es más que deuda técnica: es una superficie de ataque. Descubre por qué las suposiciones obsoletas sobre el riesgo, los atacantes automatizados y los hallazgos encadenados requieren un nuevo enfoque.