NodeJS - __proto__ & prototype Pollution
Last updated
Last updated
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Los objetos en JavaScript son esencialmente colecciones de pares clave-valor, conocidos como propiedades. Un objeto puede ser creado usando Object.create
con null
como argumento para producir un objeto vacío. Este método permite la creación de un objeto sin ninguna propiedad heredada.
Un objeto vacío es similar a un diccionario vacío, representado como {}
.
En JavaScript, las clases y las funciones están estrechamente relacionadas, siendo las funciones a menudo constructores para las clases. A pesar de la falta de soporte nativo para clases en JavaScript, los constructores pueden emular el comportamiento de las clases.
JavaScript permite la modificación, adición o eliminación de atributos de prototipo en tiempo de ejecución. Esta flexibilidad permite la extensión dinámica de las funcionalidades de las clases.
Funciones como toString
y valueOf
pueden ser alteradas para cambiar su comportamiento, demostrando la naturaleza adaptable del sistema de prototipos de JavaScript.
En la programación basada en prototipos, las propiedades/métodos son heredados por objetos de clases. Estas clases se crean añadiendo propiedades/métodos ya sea a una instancia de otra clase o a un objeto vacío.
Cabe señalar que cuando se añade una propiedad a un objeto que sirve como prototipo para otros objetos (como myPersonObj
), los objetos que heredan obtienen acceso a esta nueva propiedad. Sin embargo, esta propiedad no se muestra automáticamente a menos que se invoque explícitamente.
Los objetos de JavaScript se definen por pares clave-valor y heredan del prototipo de objeto de JavaScript. Esto significa que alterar el prototipo de Object puede influir en todos los objetos en el entorno.
Utilicemos un ejemplo diferente para ilustrar:
El acceso al prototipo de Object es posible a través de:
Al agregar propiedades al prototipo de Object, cada objeto de JavaScript heredará estas nuevas propiedades:
Para un escenario donde el uso de __proto__
está restringido, modificar el prototipo de una función es una alternativa:
Esto afecta solo a los objetos creados a partir del constructor Vehicle
, dándoles las propiedades beep
, hasWheels
, honk
e isElectric
.
Dos métodos para afectar globalmente a los objetos de JavaScript a través de la contaminación del prototipo incluyen:
Contaminar directamente el Object.prototype
:
Contaminando el prototipo de un constructor para una estructura de uso común:
Después de estas operaciones, cada objeto de JavaScript puede ejecutar los métodos goodbye
y greet
.
En un escenario donde puedes contaminar un objeto específico y necesitas llegar a Object.prototype
, puedes buscarlo con algo como el siguiente código:
Note que, así como puede contaminar atributos de objetos en JS, si tiene acceso para contaminar un array, también puede contaminar los valores del array accesibles por índices (note que no puede sobrescribir valores, por lo que necesita contaminar índices que se utilicen de alguna manera pero no se escriban).
Al generar un elemento HTML a través de JS, es posible sobrescribir el atributo innerHTML
para hacer que escriba código HTML arbitrario. Idea y ejemplo de este artículo.
Una contaminación de prototipo ocurre debido a un defecto en la aplicación que permite sobrescribir propiedades en Object.prototype
. Esto significa que, dado que la mayoría de los objetos derivan sus propiedades de Object.prototype
El ejemplo más fácil es agregar un valor a un atributo indefinido de un objeto que va a ser verificado, como:
Si el atributo admin
está indefinido es posible abusar de un PP y establecerlo en True con algo como:
El mecanismo detrás de esto implica manipular propiedades de tal manera que, si un atacante tiene control sobre ciertas entradas, puede modificar el prototipo de todos los objetos en la aplicación. Esta manipulación generalmente implica establecer la propiedad __proto__
, que, en JavaScript, es sinónimo de modificar directamente el prototipo de un objeto.
Las condiciones bajo las cuales este ataque puede ejecutarse con éxito, como se detalla en un estudio específico, incluyen:
Realizar una fusión recursiva.
Definir propiedades basadas en una ruta.
Clonar objetos.
Otros payloads:
Para más detalles, consulta este artículo En jQuery, la función $ .extend
puede llevar a la contaminación de prototipos si se utiliza incorrectamente la función de copia profunda. Esta función se usa comúnmente para clonar objetos o fusionar propiedades de un objeto por defecto. Sin embargo, cuando está mal configurada, las propiedades destinadas a un nuevo objeto pueden asignarse al prototipo en su lugar. Por ejemplo:
Esta vulnerabilidad, identificada como CVE-2019–11358, ilustra cómo una copia profunda puede modificar inadvertidamente el prototipo, lo que lleva a riesgos de seguridad potenciales, como acceso no autorizado de administrador si se verifican propiedades como isAdmin
sin una verificación adecuada de existencia.
Para más detalles, consulta este artículo
Lodash encontró vulnerabilidades similares de contaminación de prototipos (CVE-2018–3721, CVE-2019–10744). Estos problemas se abordaron en la versión 4.17.11.
Server-Side-Prototype-Pollution-Gadgets-Scanner: Extensión de Burp Suite diseñada para detectar y analizar vulnerabilidades de contaminación de prototipos del lado del servidor en aplicaciones web. Esta herramienta automatiza el proceso de escaneo de solicitudes para identificar problemas potenciales de contaminación de prototipos. Aprovecha gadgets conocidos - métodos de aprovechar la contaminación de prototipos para ejecutar acciones dañinas - enfocándose particularmente en bibliotecas de Node.js.
server-side-prototype-pollution: Esta extensión identifica vulnerabilidades de contaminación de prototipos del lado del servidor. Utiliza técnicas descritas en la contaminación de prototipos del lado del servidor.
NodeJS utiliza extensivamente Árboles de Sintaxis Abstracta (AST) en JavaScript para funcionalidades como motores de plantillas y TypeScript. Esta sección explora las vulnerabilidades relacionadas con la contaminación de prototipos en motores de plantillas, específicamente Handlebars y Pug.
El motor de plantillas Handlebars es susceptible a un ataque de contaminación de prototipos. Esta vulnerabilidad surge de funciones específicas dentro del archivo javascript-compiler.js
. La función appendContent
, por ejemplo, concatena pendingContent
si está presente, mientras que la función pushSource
restablece pendingContent
a undefined
después de agregar la fuente.
Proceso de Explotación
La explotación aprovecha el AST (Árbol de Sintaxis Abstracta) producido por Handlebars, siguiendo estos pasos:
Manipulación del Analizador: Inicialmente, el analizador, a través del nodo NumberLiteral
, impone que los valores sean numéricos. La contaminación de prototipos puede eludir esto, permitiendo la inserción de cadenas no numéricas.
Manejo por el Compilador: El compilador puede procesar un objeto AST o una plantilla de cadena. Si input.type
es igual a Program
, la entrada se trata como preanalizada, lo que puede ser explotado.
Inyección de Código: A través de la manipulación de Object.prototype
, se puede inyectar código arbitrario en la función de plantilla, lo que puede llevar a la ejecución remota de código.
Un ejemplo que demuestra la explotación de la vulnerabilidad de Handlebars:
Este código muestra cómo un atacante podría inyectar código arbitrario en una plantilla de Handlebars.
Referencia Externa: Se encontró un problema relacionado con la contaminación de prototipos en la biblioteca 'flat', como se detalla aquí: Problema en GitHub.
Referencia Externa: Problema relacionado con la contaminación de prototipos en la biblioteca 'flat'
Ejemplo de explotación de contaminación de prototipos en Python:
Pug, otro motor de plantillas, enfrenta un riesgo similar de contaminación de prototipos. La información detallada está disponible en la discusión sobre AST Injection in Pug.
Ejemplo de contaminación de prototipos en Pug:
Para reducir el riesgo de contaminación del prototipo, se pueden emplear las siguientes estrategias:
Inmutabilidad de Objetos: El Object.prototype
se puede hacer inmutable aplicando Object.freeze
.
Validación de Entrada: Las entradas JSON deben ser rigurosamente validadas contra el esquema de la aplicación.
Funciones de Fusión Seguras: Se debe evitar el uso inseguro de funciones de fusión recursivas.
Objetos Sin Prototipo: Se pueden crear objetos sin propiedades de prototipo utilizando Object.create(null)
.
Uso de Map: En lugar de Object
, se debe usar Map
para almacenar pares clave-valor.
Actualizaciones de Bibliotecas: Se pueden incorporar parches de seguridad actualizando regularmente las bibliotecas.
Herramientas de Linter y Análisis Estático: Utilizar herramientas como ESLint con los plugins apropiados para detectar y prevenir vulnerabilidades de contaminación del prototipo.
Revisiones de Código: Implementar revisiones de código exhaustivas para identificar y remediar riesgos potenciales relacionados con la contaminación del prototipo.
Capacitación en Seguridad: Educar a los desarrolladores sobre los riesgos de la contaminación del prototipo y las mejores prácticas para escribir código seguro.
Uso Cauteloso de Bibliotecas: Tener precaución al usar bibliotecas de terceros. Evaluar su postura de seguridad y revisar su código, especialmente aquellas que manipulan objetos.
Protección en Tiempo de Ejecución: Emplear mecanismos de protección en tiempo de ejecución, como el uso de paquetes npm enfocados en la seguridad que pueden detectar y prevenir ataques de contaminación del prototipo.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)