Prototype Pollution to RCE
Last updated
Last updated
Learn & practice AWS Hacking: Learn & practice GCP Hacking:
Imagina un JS real usando un código como el siguiente:
PP2RCE significa Contaminación de Prototipos a RCE (Ejecución Remota de Código).
Check that code you can see it's possible en poison envPairs
just by polluting the attribute .env
.
__proto__
Note that due to how the normalizeSpawnArguments
function from the child_process
library of node works, when something is called in order to set a new env variable for the process you just need to pollute anything.
For example, if you do __proto__.avar="valuevar"
el proceso será generado con una var llamada avar
con valor valuevar
.
However, in order for the env variable to be the first one you need to pollute the .env attribute
and (only in some methods) that var will be the first one (allowing the attack).
That's why NODE_OPTIONS
is not inside .env
in the following attack.
constructor.prototype
En lugar de almacenar la carga útil de nodejs dentro del archivo /proc/self/environ
, se almacena dentro de argv0 de /proc/self/cmdline
.
Luego, en lugar de requerir a través de NODE_OPTIONS
el archivo /proc/self/environ
, requiere /proc/self/cmdline
.
Usando las siguientes cargas útiles, es posible abusar de la variable de entorno NODE_OPTIONS de la que hemos hablado anteriormente y detectar si funcionó con una interacción DNS:
O, para evitar que los WAFs pidan el dominio:
En esta sección vamos a analizar cada función de child_process
para ejecutar código y ver si podemos usar alguna técnica para forzar que esa función ejecute código:
En los ejemplos anteriores, viste cómo activar el gadget; una funcionalidad que llama a spawn
necesita estar presente (todos los métodos de child_process
utilizados para ejecutar algo lo llaman). En el ejemplo anterior, eso era parte del código, pero ¿qué pasa si el código no lo está llamando?
/path/to/npm/scripts/changelog.js
/opt/yarn-v1.22.19/preinstall.js
Encuentra más archivos a continuación
El siguiente script simple buscará llamadas de child_process sin ningún relleno (para evitar mostrar llamadas dentro de funciones):
La técnica anterior requiere que el usuario controle la ruta del archivo que va a ser requerido. Pero esto no siempre es cierto.
Sin embargo, si el código va a ejecutar un require después de la contaminación del prototipo, incluso si no controlas la ruta que va a ser requerida, puedes forzar una diferente abusando de la contaminación del prototipo. Así que incluso si la línea de código es como require("./a_file.js")
o require("bytes")
, requerirá el paquete que contaminaste.
Por lo tanto, si se ejecuta un require después de tu contaminación del prototipo y no hay función de spawn, este es el ataque:
Encuentra un archivo .js
dentro del sistema que cuando sea requerido ejecutará algo usando child_process
Si puedes subir archivos a la plataforma que estás atacando, podrías subir un archivo así
Contamina las rutas para forzar la carga del require del archivo .js
que ejecutará algo con child_process
Contamina el entorno/cmdline para ejecutar código arbitrario cuando se llame a una función de ejecución de child_process (ver las técnicas iniciales)
Si el require realizado es absoluto (require("bytes")
) y el paquete no contiene main en el archivo package.json
, puedes contaminar el atributo main
y hacer que el require ejecute un archivo diferente.
Si se carga una ruta relativa en lugar de una ruta absoluta, puedes hacer que node cargue una ruta diferente:
Por favor, ten en cuenta que la contaminación de prototipos funciona si el atributo de un objeto que se está accediendo es undefined. Si en el código ese atributo se establece a un valor, no podrás sobrescribirlo.
Según este , cuando un proceso es generado con algún método de child_process
(como fork
o spawn
u otros), llama al método normalizeSpawnArguments
, que es un gadget de contaminación de prototipos para crear nuevas vars de entorno:
Se propuso una carga útil similar a la anterior con algunos cambios en . Las principales diferencias son:
En este , el usuario puede controlar la ruta del archivo donde se ejecutará un require
. En ese escenario, el atacante solo necesita encontrar un archivo .js
dentro del sistema que ejecute un método spawn cuando se importe.
Algunos ejemplos de archivos comunes que llaman a una función spawn cuando se importan son:
Similar al anterior, esto fue encontrado en .
En el documento también se indica que el control de contextExtensions
de algunos métodos de la biblioteca vm
podría usarse como un gadget.
Sin embargo, al igual que los métodos child_process
anteriores, ha sido arreglado en las últimas versiones.
En junio de 2022, a partir de , la var options
en lugar de un {}
es un kEmptyObject
. Lo que previene que una contaminación de prototipos afecte los atributos de options
para obtener RCE.
Al menos desde v18.4.0, esta protección ha sido implementada, y por lo tanto, los exploits de spawn
y spawnSync
que afectan los métodos ya no funcionan (¡si no se utilizan options
!).
En , la contaminación de prototipos de contextExtensions
de la biblioteca vm fue también en parte arreglada configurando opciones a kEmptyObject
en lugar de {}
.
Learn & practice AWS Hacking: Learn & practice GCP Hacking:
Check the !
Join the 💬 or the or follow us on Twitter 🐦 .
Share hacking tricks by submitting PRs to the and github repos.