4.8.5.6 Tester les injections NoSQL

Sommaire
Les bases de données NoSQL offrent des contraintes d'intégrité plus souples que les bases de données SQL traditionnelles. En nécessitant moins de contraintes relationnelles et de vérification d'intégrité, les bases NoSQL offrent souvent des bénéfices en matière de performances et de scalabilité. Cependant, ces bases sont quand-même vulnérables aux attaques par injection, même si elles n'utilisent pas la syntaxe SQL classique. Comme ces attaques par injections NoSQL peuvent s'exécuter dans un langage procédural plutôt que dans un langage déclaratif SQL, les impacts potentiels sont plus grands.

Les appels aux bases NoSQL sont écrits dans le langage de l'application, une API spécialisée, ou formattés selon une convention commune (telle que XML, JSON, LINQ, etc.). Des entrées malicieuses ciblant ces spécifications peuvent ne pas déclencher les vérifications au niveau applicatif. Par exemple, filtrer les caractères spéciaux HTML usuels tels que  n'empêchera pas les attaques contre une API JSON, où les caractères spéciaux sont.

Plus de 150 bases de données NoSQL sont aujourd'hui disponibles, fournissant des APIs dans divers langages et modèles de relations. Chacune fournie différentes fonctionnalités et restrictions. Comme il n'y a pas de langage commun à toutes, les exemples d'injection ne fonctionneront pas sur toutes les bases NoSQL. Pour cette raison, quiconque doit tester des attaques par injection NoSQL doit se familiariser avec la syntaxe, le modèle de données, et le langage de programmation sous-jacent, afin de concevoir des tests spécifiques.

Les attaques par injection NoSQL peuvent être exécutées dans des parties différentes de l'application, comparées aux injections SQL traditionnelles. Les injections SQL s'exécutent dans le moteur de base de données, alors que les variantes NoSQL vont s'exécuter dans la couche applicative ou dans la couche de bases de données, selon l'API NoSQL utilisée et le modèle de données. Typiquement, les attaques par injection NoSQL vont sexécuter là où la chaîne d'attaque est analysée, évaluée ou concaténée en un appel d'API NoSQL.

Le manque de vérification concurrentielle dans les bases NoSQL peut aussi permettre des attaques temporelles. Elles ne seront pas traitées ici. Actuellement, MongoDB est la base NoSQL la plus utilisée, donc nos exemples se concentreront sur son API.

Comment tester
Tester les vulnérabilité d'injection NoSQL dans MongoDB : L'API MongoDB attend des appels BSON (JSON binaire), et comporte un outil sécurisé d'assemblage de requête BSON. Cependant, d'après la documentation de MongoDB, du JSON non-sérialisé et des expressions JavaSctipt sont permis dans plusieurs paramètres de requête alternatifs. L'opérateur $where est l'appel d'API le plus commun permettant une entrée Javascript arbitraire.

L'opérateur $where de MongoDB est typiquement utilisé comme un simple filtre ou vérification, de la même manière qu'en SQL.

JavaScript peut aussi être évalué pour permettre des conditions plus avancées.

Exemple 1
Si un attaquant peut manipuler les données passées à l'opérateur $where, il pourra inclure du JavaScript arbitraire qui sera évalué dans la requête MongoDB. Un exemple de vulnérabilité est présenté dans le code suivant, sachant que l'entrée utilisateur est passée directement dans la requête MongoDB sans nettoyage.

Comme pour les autres tests d'injection, on n'a pas besoin d'exploiter complètement la vulnérabilité pour démontrer un problème. En injectant des caractères spéciaux adaptés au langage de l'API ciblée, et en observant les résultats, un testeur pourra déterminer si l'application valide correctement les entrées. Par exemple, dans MongoDB, si une chaîne contenant l'un des caractères spéciaux suivants est passée sans vérification, cela entraînera une erreur de la base de données.

Dnas le cas d'une injection SQL normale, une vulnérabilité similaire permettrait à un attaquant d'exécuter des commandes SQL arbitraires, accédant et manipulant les données à volonté. Cependant, comme JavaScript est un langage complet, il ne permet pas seulement de manipuler des données, mais aussi d'exécuter du code arbitraire. Par exemple, au lieu de causer seulement une erreur pendant les tests, un exploit complet serait d'utiliser des caractères spéciaux pour construire du JavaScript valide.

Cette entrée,, insérée dans $userInput dans l'exemple précédent, résulterait en l'exécution de la fonction JavaScript suivante. Cette chaîne d'attaque spécifique forecerait le serveur MongoDB à utiliser 100 de son CPU pendant 10 secondes.

Exemple 2
Même si les entrées utilisées dans les requêtes sont complétement vérifiées et nettoyées, il y a une autre manière de déclencher une injection NoSQL. Beaucoup d'instances NoSQL ont leur noms de variable réservés, indépendants du langage de programmation de l'application.

Par exemple, dans MongoDB, la syntaxe  elle-même est un opérateur de requête réservé. Il doit être passé dans la requête exactement comme montré ici, toute modification causerait une erreur de base de données. Cependant, comme  est aussi un nom de variable PHP valide, il est possible à un attaquant d'insérer du code dans la requête en créant une variable PHP nommée. La documentation PHP de MongoDB averti explicitement les développeurs : Assurez-vous s'il vous plait que pour chaque opérateur de requête (commençant par $) vous utilisez des simples quotes afin que PHP n'essaie pas de remplacer "$exists" par la valeur de la variable $exists.

Même pour une requête sans entrée utilisateur, telle que l'exemple suivant, un attaquant peut exploiter MongoDB en remplaçant l'opérateur par des données malicieuses.

Une manière d'affecter des données à une variable PHP est d'utiliser la pollution de paramètres HTTP (cf. Testing_for_HTTP_Parameter_pollution_(OTG-INPVAL-004)). En créant une variable nommée  vie une pollution de paramètres, on peut déclencher une erreur MongoDB indiquant que la requête n'est plus valide. Toute valeur de  autre que la chaîne "$where" elle-même devrait démontrer la vulnérabilité. Un attaquant développerait un exploit complet en insérant le code suivant :

Références
Whitepapers Bryan Sullivan from Adobe: "Server-Side JavaScript Injection" - https://media.blackhat.com/bh-us-11/Sullivan/BH_US_11_Sullivan_Server_Side_WP.pdf

Bryan Sullivan from Adobe: "NoSQL, But Even Less Security" - http://blogs.adobe.com/asset/files/2011/04/NoSQL-But-Even-Less-Security.pdf

Erlend from Bekk Consulting: "[Security] NOSQL-injection" - http://erlend.oftedal.no/blog/?blogid=110

Felipe Aragon from Syhunt: "NoSQL/SSJS Injection" - http://www.syhunt.com/?n=Articles.NoSQLInjection

MongoDB Documentation: "How does MongoDB address SQL or Query injection?" - http://docs.mongodb.org/manual/faq/developers/#how-does-mongodb-address-sql-or-query-injection

PHP Documentation: "MongoCollection::find" - http://php.net/manual/en/mongocollection.find.php

"Hacking NodeJS and MongoDB" - http://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html

"Attacking NodeJS and MongoDB" - http://blog.websecurify.com/2014/08/attacks-nodejs-and-mongodb-part-to.html