NoSQL Injection (NoSQLi): Cómo funcionan y cómo defenderte
Inyecciones NoSQL (NoSQLi)
Las bases de datos NoSQL son sistemas de almacenamiento de datos diseñados con el objetivo de manejar grandes volúmenes de información no estructurada (o semiestructurada), a diferencia de la información que manejan las bases de datos relacionales del modelo tradicional (SQL o Structured Query Language).
Tipos de bases de datos NoSQL más empleadas
De acuerdo con las diferentes utilidades de la información, se clasifican las bases de datos en:
- Bases de datos de Documentos: La información se almacena en forma de documentos JSON -JavaScript Object Notation, un formato liviano de serialización e intercambio de datos – o BSON -Binary JSON, formato JSON binario, codificado en binario en vez de en formato texto, como el primero). En esta categoría, destacarían CouchDB (JSON) o MongoDB (BSON).
- Bases de datos clave-valor: Los datos se almacenan como pares de clave-valor. En este sentido, son referentes Redis o DynamoDB.
- Bases de datos de grafos: Se caracterizan porque la información se emplea para priorizando el modelado de relaciones entre los datos. Las más empleadas para este tipo son Neo4j o ArangoDB.
- Bases de datos en formato de columnas: Se prioriza el almacenamiento de la información en formato de columnas. Ejemplos de este tipo serían Apache Cassandra o HBase.
¿Qué es NoSQL Injection (NoSQLi)?
Una inyección de tipo NoSQL, ocurre cuando un atacante manipula consultas de tipo NoSQL, aprovechándose de una incorrecta validación de las entradas o parámetros de usuario, permitiendo así la ejecución de sentencias no deseadas, diferentes a las específicas para las que se ha creado la funcionalidad explotada, al igual que ocurría con las inyecciones de tipo SQL. La diferencia principal con este tipo de estructuras típicas de modelos relacionales radica en que aquí no se va a trabajar con estructuras de tablas organizadas en filas y columnas, como se ha visto en el apartado anterior, ni con el lenguaje SQL, sino con lenguajes específicos de cada sistema de gestión NoSQL (JSON, BSON, CQL, etc.). Generalmente se interactuará con formatos diferentes, generalmente mediante el empleo de consultas dinámicas, menos rígidas, que permitan manipular la información con la obtención de explotar la vulnerabilidad presente en la aplicación.
Ejemplos de ataques NoSQLi en diferentes SGBDs NoSQL
A continuación, se analizarán posibles escenarios de explotación típicos dependiendo de las diferentes configuraciones en los Sistemas de Gestión de Base de Datos o gestores de base de datos NoSQL empleados.
1. MongoDB
MongoDB utiliza JSON para realizar consultas. Al almacenar el documento JSON se convertirá a su formato BSON (binario) correspondiente. Una consulta típica para verificar credenciales podría ser:
db.users.find({ username: «admin», password: «Passw0rd!»});
Ataque básico
Si la entrada no está sanitizada, un atacante podría enviar:
{ «username»: { «$ne»: null }, «password»: { «$ne»: null } }
Esto genera la consulta:
db.users.find({ username: { $ne: null }, password: { $ne: null } })
Así pues, el resultado omitirá la validación de credenciales y el atacante obtendrá acceso al sistema, de manera similar a como se podría evadir con un SQLi tradicional los mecanismos de autenticación de un formulario con la inyección clásica ‘ OR 1=1 — o similar.
Nótese que si se emplease db.users.findOne recuperaría el primer usuario de la base de datos, que generalmente suele ser el administrador.
2. Redis
Redis es una base de datos clave-valor que permite comandos como GET y SET. Un ataque típico podría involucrar la manipulación de claves para obtener información diferente de la que se pretende recuperar.
Supongamos que una aplicación consulta claves con:
GET user:admin
Ataque básico
Un atacante podría inyectar:
GET user:*
Mediante el uso del comodín o wildcard ‘*’ se devolverán todas las claves que coincidan con el patrón y, por ende, enumerar todos los usuarios de la aplicación.
3. Apache Cassandra
Cassandra utiliza CQL (Cassandra Query Language), similar a SQL, pero adaptado a su modelo de columnas. Es por esto por lo que quizás los ataques NoSQLi relacionados con este sistema de consultas recuerdan más al tradicional SQLi que el resto de los analizados en este post.
Una consulta típica para buscar usuarios puede ser:
SELECT * FROM users WHERE username = ‘admin’ AND password = ‘Passw0rd!’;
Ataque básico
De esta forma, un atacante podría inyectar:
‘ OR ‘1’=’1
Lo que generaría:
SELECT * FROM users WHERE username = ‘**’ OR ‘1’=’1**’ AND password = ‘
… accediendo de esta forma a todos usuarios del sistema.
4. Neo4j
Neo4j utiliza Cypher como lenguaje de consulta. Una consulta típica para buscar nodos podría ser:
MATCH (u:User {username: ‘admin’, password: ‘Passw0rd!’}) RETURN u;
Ataque básico
Un atacante podría inyectar:
MATCH (u) RETURN u //
… y, en consecuencia, se podrían devolver todos los nodos de la base de datos.
Técnicas de ofuscación y evasión
Los sistemas de detección como WAF (Web Application Firewall) suelen bloquear patrones comunes de inyección. Sin embargo, los atacantes pueden usar técnicas avanzadas para evadirlos, tal y como ya se vio en los ataques de SQLi, y otros tipos de inyecciones. De manera análoga a las bases de datos SQL, pero aplicado a este tipo de bases de datos, se pueden emplear las siguientes técnicas:
1. Codificación
Codificar los caracteres especiales puede ayudar a evitar que los WAF detecten patrones sospechosos.
Codificación hexadecimal
Convertir caracteres a su representación en hexadecimal:
{ «$ne»: null } → %7B%20%22%24ne%22%3A%20null%20%7D
Codificación Base64
Codificar el payload completo en base64 (y decodificar después en el cliente):
{ «$ne»: null } → eyAiJG5lIjogbnVsbCB9Cg==
2. Comentarios
Esta técnica consiste en insertar comentarios para evitar reglas de detección. Por ejemplo, en Neo4j, se puede inyectar el código visto antes para recuperar todos los usuarios, pero insertando previamente un comentario:
MATCH /* loquesea */ (u) RETURN u
3. Concatenación
Empleando la concatenación (+), al igual que ocurría con la evasión en SQLi, se pueden fragmentar cadenas para separar el payload y así evitar detecciones directas. Por ejemplo, en el caso de MongoDB:
{ «username»: { «$n» + «e»: null } }
4. Uso de caracteres de control o espacios Unicode (caracteres invisibles)
A veces el uso ciertos caracteres que no modifican realmente la consulta, pueden emplearse en las inyecciones para romper los patrones de detección de los WAF. Por ejemplo, en el caso visto para Redis, incorporar antes del uso del comodín (*) el carácter Unicode equivalente al «espacio de ancho cero» (carácter unicode 200B).
GET user:\u200B*
Medidas de prevención
1. Validación y saneamiento
• Utilización de validaciones estrictas en el lado del servidor.
• Rechazo de caracteres especiales o estructuras no esperadas para la realización de la funcionalidad específica. Mejor hacerlo acotando por los valores deseados que se espera recibir que por valores más «abiertos» que puedan ser aprovechados por un atacante o funciones de escape que puedan ser incompletas. En este último caso, y si fuese necesario, emplear el uso de bibliotecas y funcionalidades preexistentes. Siempre se debe buscar «no reinventar la rueda» en este sentido.
2. Uso de bibliotecas seguras
Establecer el uso de operadores seguros. Por ejemplo, emplear $eq, en MongoDB:
db.users.find({ username: { $eq: «admin» }, password: { $eq: «Passw0rd!» } });
De esta manera se evitaría la construcción de consultas dinámicas, demasiado «abiertas». Habría que tener esto en cuenta también para aquellos casos donde se emplean expresiones regulares.
3. Principio de Mínimos Privilegios o limitación de los permisos del usuario.
Siempre se recomienda limitar los permisos del usuario empleado para acceder únicamente a la información a la que le es necesario acceder y a ninguna otra, estando limitado al ámbito de la base de datos en cuestión.
4. Uso de WAF (Web Application Firewall)
Se debería emplear el WAF para bloquear patrones específicos de NoSQLi, pero sin olvidar nunca seguir buenas prácticas de desarrollo seguro para evitar que la evasión de dichos patrones, puedan derivar en un ataque exitoso contra la aplicación.
Conclusión
Al considerar las bases de datos NoSQL por la ventaja competitiva que ofrecen en cuanto a flexibilidad, escalabilidad y manejo de grandes volúmenes de información, también se abre la puerta a nuevas superficies de ataque, con métodos similares a las tradicionales SQLi, como es el caso de las NoSQLi. A diferencia de estos ataques tradicionales, aquí se aprovecha la naturaleza no estructurada de la información, generalmente mediante la manipulación de los archivos JSON/BSON asociados.
Es fundamental que, tanto los desarrolladores como los administradores de sistemas y los administradores de bases de datos, realicen un enfoque de seguridad multicapa, que pase desde una correcta validación y saneamiento de los parámetros de entrada (adaptado a los nuevos sistemas de gestión empleados), el uso de bibliotecas seguras y una configuración adecuada (y limitada) en cuanto al sistema y los permisos empleados.
Además, la compresión de las técnicas de evasión utilizadas por los atacantes, y la realización de pruebas periódicas de seguridad pueden ayudar a mejorar las defensas contra este tipo de amenaza.
Por último, aunque NoSQLi comparte similitudes con SQLi, las diferencias entre los lenguajes y estructuras NoSQL empleados requerirán enfoques diferentes y únicos para asegurar estos sistemas frente a diferentes ataques.
Roberto Trigo, Consultor de ciberseguridad en Zerolynx.
Powered by WPeMatico