La inyección NoSQL es una vulnerabilidad en la que un atacante puede interferir con las consultas que realiza una aplicación a una base de datos NoSQL. La inyección NoSQL puede permitir a un atacante:
- Omitir mecanismos de autenticación o protección.
- Extraer o editar datos.
- Causar una denegación de servicio.
- Ejecutar código en el servidor.
Las bases de datos NoSQL almacenan y recuperan datos en un formato distinto a las tablas relacionales SQL tradicionales. Utilizan una amplia gama de lenguajes de consulta en lugar de un estándar universal como SQL y tienen menos restricciones relacionales.
Tipos de inyección NoSQL
Hay dos tipos diferentes de inyección NoSQL:
- Inyección de sintaxis: esto ocurre cuando puedes romper la sintaxis de la consulta NoSQL, lo que te permite inyectar tu propia carga útil. La metodología es similar a la utilizada en la inyección SQL . Sin embargo, la naturaleza del ataque varía significativamente, ya que las bases de datos NoSQL utilizan una variedad de lenguajes de consulta, tipos de sintaxis de consulta y diferentes estructuras de datos.
- Inyección de operador: esto ocurre cuando puede utilizar operadores de consulta NoSQL para manipular consultas.
En este tema, veremos cómo probar las vulnerabilidades NoSQL en general y luego nos centraremos en explotar las vulnerabilidades en MongoDB, que es la base de datos NoSQL más popular. También proporcionamos algunos laboratorios para que pueda practicar lo que ha aprendido.
Encuentre y solucione rápidamente las vulnerabilidades que ponen sus aplicaciones web en riesgo de ataque.
Conocer …
Inyección de sintaxis NoSQL
Potencialmente puede detectar vulnerabilidades de inyección NoSQL intentando romper la sintaxis de la consulta. Para hacer esto, pruebe sistemáticamente cada entrada enviando cadenas difusas y caracteres especiales que desencadenen un error de base de datos o algún otro comportamiento detectable si la aplicación no los desinfecta o filtra adecuadamente.
Si conoce el idioma API de la base de datos de destino, utilice caracteres especiales y cadenas difusas que sean relevantes para ese idioma. De lo contrario, utilice una variedad de cadenas difusas para apuntar a múltiples lenguajes API.
Detectando inyección de sintaxis en MongoDB
Considere una aplicación de compras que muestre productos en diferentes categorías. Cuando el usuario selecciona la categoría Fizzy drinks, su navegador solicita la siguiente URL:
https://insecure-website.com/product/lookup?category=fizzy
Esto hace que la aplicación envíe una consulta JSON para recuperar productos relevantes de la product colección en la base de datos MongoDB:
this.category == 'fizzy'
Para probar si la entrada puede ser vulnerable, envíe una cadena difusa en el valor del categoryparámetro. Una cadena de ejemplo para MongoDB es:
'"`{
;$Foo}
$Foo \xYZ
Utilice esta cadena fuzz para construir el siguiente ataque:
https://insecure-website.com/product/lookup?category='%22%60%7b%0d%0a%3b%24Foo%7d%0d%0a%24Foo%20%5cxYZ%00
Si esto provoca un cambio con respecto a la respuesta original, esto puede indicar que la entrada del usuario no se filtró o desinfectó correctamente.

Determinar qué caracteres se procesan
Para determinar qué caracteres la aplicación interpreta como sintaxis, puede inyectar caracteres individuales. Por ejemplo, podría enviar ', lo que da como resultado la siguiente consulta de MongoDB:
this.category == '''
Si esto provoca un cambio con respecto a la respuesta original, esto puede indicar que el 'carácter ha roto la sintaxis de la consulta y ha provocado un error de sintaxis. Puede confirmar esto enviando una cadena de consulta válida en la entrada, por ejemplo escapando la cita:
this.category == '\''
Si esto no causa un error de sintaxis, puede significar que la aplicación es vulnerable a un ataque de inyección.
Confirmar el comportamiento condicional
Después de detectar una vulnerabilidad, el siguiente paso es determinar si se pueden influir en las condiciones booleanas utilizando la sintaxis NoSQL.
Para probar esto, envíe dos solicitudes, una con una condición falsa y otra con una condición verdadera. Por ejemplo, podría utilizar las declaraciones condicionales ' && 0 && 'x y ' && 1 && 'x de la siguiente manera:
https://insecure-website.com/product/lookup?category=fizzy'+%26%26+0+%26%26+'x
https://insecure-website.com/product/lookup?category=fizzy'+%26%26+1+%26%26+'x
Si la aplicación se comporta de manera diferente, esto sugiere que la condición falsa afecta la lógica de la consulta, pero la condición verdadera no. Esto indica que inyectar este estilo de sintaxis afecta una consulta del lado del servidor.
Anulando las condiciones existentes
Ahora que ha identificado que puede influir en las condiciones booleanas, puede intentar anular las condiciones existentes para aprovechar la vulnerabilidad. Por ejemplo, puede inyectar una condición de JavaScript que siempre se evalúe como verdadera, como por ejemplo '||1||':
https://insecure-website.com/product/lookup?category=fizzy%27%7c%7c%31%7c%7c%27
Esto da como resultado la siguiente consulta MongoDB:
this.category == 'fizzy'||'1'=='1'
Como la condición inyectada siempre es verdadera, la consulta modificada devuelve todos los elementos. Esto le permite ver todos los productos en cualquier categoría, incluidas las categorías ocultas o desconocidas.
También puedes agregar un carácter nulo después del valor de la categoría. MongoDB puede ignorar todos los caracteres después de un carácter nulo. Esto significa que se ignora cualquier condición adicional en la consulta de MongoDB. Por ejemplo, la consulta puede tener una this.released restricción adicional:
this.category == 'fizzy' && this.released == 1
La restricción this.released == 1se utiliza para mostrar únicamente los productos que se lanzan. Para productos inéditos, presumiblemente this.released == 0.
En este caso, un atacante podría construir un ataque de la siguiente manera:
https://insecure-website.com/product/lookup?category=fizzy'%00
Esto da como resultado la siguiente consulta NoSQL:
this.category == 'fizzy'\u0000' && this.released == 1
Si MongoDB ignora todos los caracteres después del carácter nulo, esto elimina el requisito de que el campo liberado se establezca en 1. Como resultado, fizzy se muestran todos los productos de la categoría, incluidos los productos no lanzados.

Inyección de sintaxis NoSQL
Las bases de datos NoSQL suelen utilizar operadores de consulta, que proporcionan formas de especificar las condiciones que deben cumplir los datos para incluirse en el resultado de la consulta. Ejemplos de operadores de consulta de MongoDB incluyen:
$where– Coincide con documentos que satisfacen una expresión de JavaScript.$ne– Coincide con todos los valores que no son iguales a un valor especificado.$in– Coincide con todos los valores especificados en una matriz.$regex– Selecciona documentos donde los valores coinciden con una expresión regular especificada.
Es posible que pueda inyectar operadores de consulta para manipular consultas NoSQL. Para hacer esto, envíe sistemáticamente diferentes operadores en una variedad de entradas de usuario y luego revise las respuestas en busca de mensajes de error u otros cambios.
Envío de operadores de consulta
En los mensajes JSON, puede insertar operadores de consulta como objetos anidados. Por ejemplo, {"username":"wiener"} se convierte en {"username":{"$ne":"invalid"}}.
Para entradas basadas en URL, puede insertar operadores de consulta mediante parámetros de URL. Por ejemplo, username=wiener se convierte en username[$ne]=invalid. Si esto no funciona, puedes intentar lo siguiente:
- Convierta el método de solicitud de
GETaPOST. - Cambie el
Content-Typeencabezado aapplication/json. - Agregue JSON al cuerpo del mensaje.
- Inyecte operadores de consulta en JSON.
Detección de inyección de operador en MongoDB
Considere una aplicación vulnerable que acepta un nombre de usuario y contraseña en el cuerpo de una POST solicitud:
{"username":"wiener","password":"peter"}
Pruebe cada entrada con una variedad de operadores. Por ejemplo, para probar si la entrada del nombre de usuario procesa el operador de consulta, puede intentar la siguiente inyección:
{"username":{"$ne":"invalid"},"password":{"peter"}}
Si se aplica el $ne operador, se consulta a todos los usuarios cuyo nombre de usuario no sea igual a invalid.
Si tanto el nombre de usuario como la contraseña procesan al operador, es posible omitir la autenticación utilizando la siguiente carga útil:
{"username":{"$ne":"invalid"},"password":{"$ne":"invalid"}}
Esta consulta devuelve todas las credenciales de inicio de sesión en las que tanto el nombre de usuario como la contraseña no son iguales invalid. Como resultado, habrá iniciado sesión en la aplicación como el primer usuario de la colección.
Para apuntar a una cuenta, puede crear una carga útil que incluya un nombre de usuario conocido o un nombre de usuario que haya adivinado. Por ejemplo:
{"username":{"$in":["admin","administrator","superadmin"]},"password":{"$ne":""}}
El mejor software y aprendizaje de su clase para ingenieros de seguridad y evaluadores de penetración.
Conocer …
Explotar la inyección de sintaxis para extraer datos
En muchas bases de datos NoSQL, algunos operadores o funciones de consulta pueden ejecutar código JavaScript limitado, como $where el operador y mapReduce() la función de MongoDB. Esto significa que, si una aplicación vulnerable utiliza estos operadores o funciones, la base de datos puede evaluar JavaScript como parte de la consulta. Por lo tanto, es posible que pueda utilizar funciones de JavaScript para extraer datos de la base de datos.
Exfiltración de datos en MongoDB
Considere una aplicación vulnerable que permita a los usuarios buscar otros nombres de usuario registrados y muestre su función. Esto desencadena una solicitud a la URL:
https://insecure-website.com/user/lookup?username=admin
Esto da como resultado la siguiente consulta NoSQL de la users colección:
{"$where":"this.username == 'admin'"}
Como la consulta utiliza el $where operador, puede intentar inyectar funciones de JavaScript en esta consulta para que devuelva datos confidenciales. Por ejemplo, podría enviar la siguiente carga útil:
admin' && this.password[0] == 'a' || 'a'=='b
Esto devuelve el primer carácter de la cadena de contraseña del usuario, lo que le permite extraer la contraseña carácter por carácter.
También puede utilizar la match() función JavaScript para extraer información. Por ejemplo, la siguiente carga útil le permite identificar si la contraseña contiene dígitos:
admin' && this.password.match(/\d/) || 'a'=='b
Identificar nombres de campos
Debido a que MongoDB maneja datos semiestructurados que no requieren un esquema fijo, es posible que necesites identificar campos válidos en la colección antes de poder extraer datos mediante la inyección de JavaScript.
Por ejemplo, para identificar si la base de datos MongoDB contiene un password campo, puede enviar la siguiente carga útil:
https://insecure-website.com/user/lookup?username=admin'+%26%26+this.password!%3d'
Envíe la carga útil nuevamente para un campo existente y para un campo que no existe. En este ejemplo, sabes que el username campo existe, por lo que podrías enviar las siguientes cargas útiles:
admin' && this.username!='
admin' && this.foo!='
Si el password campo existe, esperaría que la respuesta fuera idéntica a la respuesta del campo existente ( username), pero diferente a la respuesta del campo que no existe ( foo).
Si desea probar diferentes nombres de campos, puede realizar un ataque de diccionario, utilizando una lista de palabras para recorrer diferentes nombres de campos potenciales.
Explotación de la inyección del operador NoSQL para extraer datos
Incluso si la consulta original no utiliza ningún operador que le permita ejecutar JavaScript arbitrario, es posible que pueda inyectar uno de estos operadores usted mismo. Luego puede usar condiciones booleanas para determinar si la aplicación ejecuta cualquier JavaScript que inyecte a través de este operador.
Inyectar operadores en MongoDB
Considere una aplicación vulnerable que acepta nombre de usuario y contraseña en el cuerpo de una POSTsolicitud:
{"username":"wiener","password":"peter"}
Para probar si puede inyectar operadores, puede intentar agregar el $where operador como parámetro adicional y luego enviar una solicitud donde la condición se evalúe como falsa y otra que se evalúe como verdadera. Por ejemplo:
{"username":"wiener","password":"peter", "$where":"0"}
{"username":"wiener","password":"peter", "$where":"1"}
Si hay una diferencia entre las respuestas, esto puede indicar que $wherese está evaluando la expresión JavaScript en la cláusula.
Extrayendo nombres de campos
Si ha inyectado un operador que le permite ejecutar JavaScript, es posible que pueda utilizar el keys()método para extraer el nombre de los campos de datos. Por ejemplo, podría enviar la siguiente carga útil:
"$where":"Object.keys(this)[0].match('^.{0}a.*')"
Esto inspecciona el primer campo de datos en el objeto de usuario y devuelve el primer carácter del nombre del campo. Esto le permite extraer el nombre del campo carácter por carácter.
Exfiltración de datos mediante operadores
Alternativamente, es posible que pueda extraer datos utilizando operadores que no le permitan ejecutar JavaScript. Por ejemplo, es posible que pueda utilizar el $regex operador para extraer datos carácter por carácter.
Considere una aplicación vulnerable que acepta un nombre de usuario y contraseña en el cuerpo de una POST solicitud. Por ejemplo:
{"username":"myuser","password":"mypass"}
Podrías comenzar probando si el $regex operador se procesa de la siguiente manera:
{"username":"admin","password":{"$regex":"^.*"}}
Si la respuesta a esta solicitud es diferente a la que recibe cuando envía una contraseña incorrecta, esto indica que la aplicación puede ser vulnerable. Puede utilizar el $regex operador para extraer datos carácter por carácter. Por ejemplo, la siguiente carga útil comprueba si la contraseña comienza con a:
{"username":"admin","password":{"$regex":"^a*"}}
Inyección basada en el tiempo
A veces, desencadenar un error de base de datos no provoca una diferencia en la respuesta de la aplicación. En esta situación, es posible que aún pueda detectar y explotar la vulnerabilidad mediante la inyección de JavaScript para activar un retraso de tiempo condicional.
Para realizar una inyección NoSQL basada en tiempos:
- Cargue la página varias veces para determinar un tiempo de carga base.
- Inserte una carga útil basada en sincronización en la entrada. Una carga útil basada en tiempo provoca un retraso intencional en la respuesta cuando se ejecuta. Por ejemplo,
{"$where": "sleep(5000)"}provoca un retraso intencionado de 5000 ms en una inyección exitosa. - Identifique si la respuesta se carga más lentamente. Esto indica una inyección exitosa.
Las siguientes cargas útiles basadas en tiempos activarán un retraso de tiempo si la contraseña comienza con la letra a:
admin'+function(x){var waitTill = new Date(new Date().getTime() + 5000);while((x.password[0]==="a") && waitTill > new Date()){};}(this)+'
admin'+function(x){if(x.password[0]==="a"){sleep(5000)};}(this)+'
Ataques avanzados e inyecciones de JavaScript
Las consultas de MongoDB admiten un operador de uso común $where, que introduce posibilidades de ataques NoSQL graves que incluyen objetos JavaScript.
Por ejemplo, un desarrollador podría querer utilizar el $where operador de la siguiente manera para acceder a un registro de un usuario en particular:
$query = array('$where' => 'this.name === \''.$name.'\'');
En esta situación, el atacante puede proporcionar el siguiente truco de comparación de cadenas vacías como $name:
'; return '' == '
Como resultado, la consulta será:
"$where": "this.name === ''; return '' == ''"
Y el atacante recibirá la lista completa de usuarios.
Dado que el $where operador en realidad se evalúa como código JavaScript, el atacante también podría pasar una cadena maliciosa que incluya JavaScript arbitrario, por ejemplo:
'; while(true){}'
Cómo evitar las inyecciones NoSQL
Para evitar inyecciones de NoSQL, siempre debe tratar la entrada del usuario como si no fuera de confianza. Esto es lo que puede hacer para validar la entrada del usuario:
- Utilice una biblioteca de desinfección. Por ejemplo, mongo-sanitize o mongoose.
- Si no puede encontrar una biblioteca para su entorno, convierta la entrada del usuario al tipo esperado. Por ejemplo, convierta nombres de usuarios y contraseñas en cadenas.
- En el caso de MongoDB, nunca utilice los operadores
where,mapReduceugroupcon la entrada del usuario porque estos operadores permiten al atacante inyectar JavaScript y, por lo tanto, son mucho más peligrosos que otros. Para mayor seguridad, configúrelojavascriptEnabledenfalsemongod.conf, si es posible. - Además, utilice siempre el modelo de privilegios mínimos: ejecute su aplicación con los privilegios más bajos posibles para que, incluso si es explotada, el atacante no pueda acceder a otros recursos.
NORTH NETWORKS es Distribuidor Oficial y brinda licencias nuevas, renovaciones y servicios profesionales de las herramientas mas importantes.
Pongase en contacto y le ayudaremos a analizar sus necesidades para poder brindarle la herramienta que mejor se ajuste a sus requerimientos.
Si te ha gustado, ¡compártelo con tus amigos!



