Inyección NoSQL


La vulnerabilidad de inyección NoSQL puede ser utilizada por un actor malicioso para acceder y modificar datos confidenciales, incluidos nombres de usuario, direcciones de correo electrónico, hash de contraseña y tokens de inicio de sesión. Si esto se encadena con otras vulnerabilidades, puede conducir a una toma de control completa del sitio.

¿Qué es una base de datos NoSQL?

Las bases de datos NoSQL (no SQL o no relacionales) han existido desde hace un buen tiempo, pero el término ganó mayor popularidad a principios de 2009. Existen diferentes tipos y ejemplos de bases de datos NoSQL, algunas se mencionan aquí:

Key-Value Key-Document Column-Family Graph
Redis MongoDB Cassandra Neo4j
MemcacheDB CouchDB HBase OrientDB

Las principales formas en que las bases de datos NoSQL difieren de las bases de datos SQL más tradicionales son:

  • Sin lenguaje de consulta estructurado
  • Esquema dinámico
  • Escalabilidad horizontal
  • Los campos se pueden agregar a los documentos sobre la marcha sin afectar el resto de los datos.

La base de datos NoSQL más utilizada es, por mucho, MongoDB. [^ 1] Por esta razón, los ejemplos en esta publicación también se basan en MongoDB.

Encontrar la inyección

Encuentra dónde interactúa la aplicación con el servidor de la base de datos. Algunos ejemplos son:

  • Formularios de autenticación
  • Filtrar o buscar formularios
  • Encabezados y cookies

Después de enumerar los campos de entrada que podrían usarse en una consulta de base de datos, el probador debe intentar modificar los valores para provocar un error o un comportamiento inesperado.

Si no hay sanitización en los campos de entrada, algunos caracteres pueden interrumpir la consulta, por ejemplo, ' " \ ; { } ( )

Para la detección automática, NoSQLMap a veces se puede aprovechar lo que esté al alcance la mano, aunque los casos más avanzados casi siempre requieren pruebas manuales, análisis estático y revisión de código.

Inyección de JavaScript en consultas

Aunque la API MongoDB generalmente espera datos BSON (JSON binario), se permiten algunas expresiones JSON y JavaScript no serializadas. Para MongoDB, el operador más común es $where, que filtra los resultados de manera similar a WHERE en SQL. Otros incluyen mapReduce y group.

Echemos un vistazo al siguiente código:

Posts.find({ $where: `this.hidden == false && this.author == '${req.query.author}'` }, (err, posts) => { ... });

Normalmente, esta consulta devolvería publicaciones realizadas por el autor especificado. Sin embargo, al solicitar GET /posts?author='+||+''==', la consulta de JavaScript se convierte en esto:

this.hidden == false && this.author == '' || ''==''

Esto arrojaría como resultado las publicaciones de todos los autores.

También es posible un ataque de denegación de servicio al solicitar GET /posts?author=';while(1);'

Se puede encontrar una lista más larga de entradas maliciosas en GitHub.

Tautología

Si se envía un formulario como JSON, cambiar un valor de campo a un operador de consulta MongoDB podría crear una tautología, una expresión que siempre es verdadera. Por ejemplo, considera el siguiente código vulnerable que busca a un usuario por el nombre de usuario y la contraseña especificados en la solicitud POST enviada:

User.findOne({ username: req.body.username, password: req.body.password }, (err, user) => { ... });

Si el cuerpo de la solicitud está codificado como JSON y la contraseña se cambia de una cadena a una expresión de consulta que se evalúa como verdadera, la verificación de la contraseña se vuelve irrelevante y un atacante puede autenticarse a sí mismo como cualquier usuario. Para eso, vamos a utilizar el selector de consulta $ne, que encuentra los documentos donde el valor del campo no es igual al valor especificado.

{
    "username": "admin",
    "password": {"$ne": ""}
}

Lo mismo se puede hacer con la codificación más común para formularios HTML, el método de urlencoding. El módulo qs de NodeJS analiza la siguiente cadena de consulta en el mismo JSON:

username=admin&password[$ne]=

Mitigación

  • No crees consultas a partir de cadenas, usa API seguras y declaraciones preparadas.
  • Valida la entrada para detectar valores maliciosos, teniendo en cuenta también la validación de los tipos de entrada contra los tipos esperados.
  • Para minimizar el daño potencial de un ataque de inyección exitoso, no asignes derechos de acceso de tipo administrador o DBA a las cuentas de tu aplicación.

De la documentación de MongoDB:[^ 2]

Puedes expresar la mayoría de las consultas en MongoDB sin JavaScript y para consultas que requieren JavaScript, puedes mezclar JavaScript y no JavaScript en una sola consulta. Coloca todos los campos proporcionados por el usuario directamente en un campo BSON y pasa el código JavaScript al campo $where.

Puedes deshabilitar toda la ejecución de JavaScript del lado del servidor en MongoDB pasando la opción --noscripting en la línea de comando o configurando security.javascriptEnabled en un archivo de configuración.

Conclusión

NoSQL no significa que no habrá ninguna inyección: las bases de datos NoSQL sufren los mismos riesgos de seguridad que sus contrapartes SQL. Usar incluso el almacén de datos más seguro no previene los ataques de inyección si la aplicación no se ha desarrollado teniendo en cuenta las prácticas de codificación segura.

Kert Ojasoo