4.8.5.6 Tester les injections NoSQL

From OWASP
Jump to: navigation, search
This article is part of the new OWASP Testing Guide v4.
Back to the OWASP Testing Guide v4 ToC: https://www.owasp.org/index.php/OWASP_Testing_Guide_v4_Table_of_Contents Back to the OWASP Testing Guide Project: https://www.owasp.org/index.php/OWASP_Testing_Project


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 [1] plutôt que dans un langage déclaratif SQL [2], 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 [3], 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 [4]. 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.

db.myCollection.find( { $where: "this.credits == this.debits" } );


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

db.myCollection.find( { $where: function() { return obj.credits - obj.debits < 0; } } );


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.

db.myCollection.find( { active: true, $where: function() { return obj.credits - obj.debits < $userInput; } } );;


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, 0;var date=new Date(); do{curDate = new Date();}while(curDate-date<10000), 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.

function() { return obj.credits - obj.debits < 0;var date=new Date(); do{curDate = new Date();}while(curDate-date<10000); }


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 $where 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 $where 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 $where. 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.

db.myCollection.find( { $where: function() { return obj.credits - obj.debits < 0; } } );


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 $where 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 $where 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 : "$where: function() { //arbitrary JavaScript here }"


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