Annonce

Réduire
Aucune annonce.

Initiation aux injections XPATH

Réduire
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • Tutoriel Initiation aux injections XPATH

    Bonjour à tous !

    Pour bien comprendre ce tutoriel, des connaissances en XML et en XPATH sont les bienvenues, ainsi qu’une connaissance en injection SQL facilitera la compréhension de ce qui suit. Dans le cas inverse, ben je vous propose de faire un tour ici.
    Bien sûr, ce tutoriel est à but informatif. Nous verrons comment exploiter cette faille pour savoir comment s'en protéger.

    1. Outils
    Pour commencer, je vais vous donner un outil permettant de tester vos requêtes XPATH (ici) et un exemple de fichier XML sur lequel nous allons travailler.
    Code:
    <?xml version="1.0" encoding="UTF-8" ?>
    <users>
    	<user type="administrator">
    		<username>admin</username>
    		<password>Passw0rd</password>
    		<email>[email protected]</email>
    		<description>An admin account</description>
    	</user>
    	<user type="member">
    		<username>member</username>
    		<password>m3mb3r</password>
    		<email>[email protected]</email>
    		<description>And a member account</description>
    	</user>
    </users>

    2. Bypasser une authentification
    Code:
    <?php
    	$header = "<html><head><title>Labs hack XPATH injection</title></head><body><div>";
    	$footer = "</div></body></html>";
    	
    	if(isset($_GET['username']) && isset($_GET['password']) && !empty($_GET['username']) && !empty($_GET['password'])){
    		$xml = simplexml_load_file('users.xml');
    		$xpath = "//user[username='" . $_GET['username'] . "' and password='" . $_GET['password'] . "']";
    		$element = $xml->xpath($xpath);
    
    		if(count($element) > 0){
    			print $header;
    			print "<h1>You're authenticated</h1>";
    			print $footer;
    		} else {
    			print $header;
    			print "<h1>You're not authenticated</h1><br />";
    			?>	
    				<form action="" method="GET">
    					<label for="username">Username</label>
    					<input type="text" id="username" name="username" />
    					<br />
    					<label for="password">Password</label>
    					<input type="password" id="password" name="password" />
    					<br />
    					<input type="submit" value="Login" />
    				</form>
    			<?php
    			print $footer;
    		}
    	} else {
    		print $header;
    		?>
    	
    			<form action="" method="GET">
    				<label for="username">Username</label>
    				<input type="text" id="username" name="username" />
    				<br />
    				<label for="password">Password</label>
    				<input type="password" id="password" name="password" />
    				<br />
    				<input type="submit" value="Login" />
    			</form>
    		<?php
    		print $footer;
    	}
    ?>
    Ce petit code PHP ci-dessus est un simple formulaire qui demande un login et mot de passe. S’ils correspondent à un utilisateur présent dans le fichier XML, alors un message d’authentification est affiché, sinon, ben vous ne l’êtes pas.

    Testons donc avec comme login : « admin » et le mot de passe : « Passw0rd ». Ça marche ! Enfin, heureusement, étant donné que les identifiants sont visibles.

    Regardons de plus près. Ce script PHP est exploitable à la ligne 7

    Code:
    $xpath = "//user[username='" . $_GET['username'] . "' and password='" . $_GET['password'] . "']";
    Si vous remplacez les variables « $_GET » par les identifiants, vous obtenez ceci :
    Code:
    $xpath = "//user[username='admin' and password='Passw0rd']";
    Maintenant, essayons de se ré-authentifier avec les identifiants « a' or 1=1 or 'a'=' » et « toto ». Et ça marche encore ! Mais que s’est-il passé ? Nous avons simplement réécris les conditions de la requête, celle sur l’élément « username » pour être plus précis. Ceux qui ont déjà des connaissances en injection SQL ne devrait pas être dépaysagés. Voici le code vu du plus près pour bien comprendre :

    Code:
    $xpath = "//user[username='a' or 1=1 or 'a'='a' and password='toto']";
    Ce qui donne de façon plus lisible :

    Code:
    $xpath = "//user[username='a' or 1=1 or ('a'='a' and password='toto')]";
    Comme vous pouvez le voir, nous avons pu isoler la condition « and » qui posait problème en rajoutant des deux conditions « or ». De plus, la condition « 1=1 » étant toujours vérifié, la requête renverra donc tous les utilisateurs du document XML. Pour finir, le script PHP ne vérifiant qu’au moins un élément est renvoyé pour authentifié l’utilisateur, l’authentification est donc permise.

    Voici donc le premier niveau d’injection XPATH, je vous laisse le plaisir de tester plusieurs choses à partir d’ici.


    3. Récupérer des informations
    Ce que nous allons voir maintenant, c’est d’injecter du code, non pas pour passer une contraintes, mais récupérer les informations du document XML. Voici un script PHP simple qui permet de rechercher des noms d’utilisateurs à partir d’une chaine envoyée en paramètre.
    Code:
    <html>
    	<head>
    		<title>Labs hack XPATH injection</title>
    	</head>
    	<body>
    		<div>
    			<form action="" method="GET">
    				<fieldset>
    					<legend>Search Email</legend>
    					<input type="text" id="search" name="search" />
    					<input type="submit" value="search" />
    				</fieldset>
    			</form>
    		</div>
    		<div>
    <?php
    	if(isset($_GET['search'])  && !empty($_GET['search'])){
    		$xml = simplexml_load_file('users.xml');
    		$xpath = "//user/username[contains(.,'" . $_GET['search'] . "')]";
    		$elements = $xml->xpath($xpath);
    
    		if(count($elements) > 0){
    			foreach($elements as $e)
    				print "User : $e<br />";
    		} else 
    			print "0 result<br />";
    	} else 
    		print "0 result<br />";
    
    ?>
    		</div>
    	</body>
    </html>
    Je vous laisse la joie de tester si ce script marche bien en l’essayant. Cette fois, c’est la ligne suivante qui est vulnérable :
    Code:
    $xpath = "//user/username[contains(.,'" . $_GET['search'] . "')]";
    Pour ceux qui ne connaissent pas bien le XPATH, il existe plusieurs fonctions spécifiques au XPATH permettant des prédicats plus avancées. La fonction « contains » en fait partie. Le premier paramètre est le texte dans lequel on recherche, ici le « . » fait référence au nœud actuel : username, puis le deuxième paramètre est la chaine à rechercher.

    Sachant cela, essayons de rentrer l’expression suivante : « a') or ('a'='a ». En regardant bien, nous obtenons :
    Code:
    $xpath = "//user/username[contains(.,'a') or ('a'='a')]";
    C’est similaire à l’injection que nous avons vu précédemment, nous avons juste réécris la contrainte. Pour ma part, je trouve ça bien mais pas top. En effet, je vous dis au début de ce chapitre que nous allons récupérer les informations du XML. Normalement, vous devriez avoir une petite idée de comment faire. Mais je vous donne la solution : « a') or ('a'='a')]/../*[('1'='1 ». Ce qui donne :
    Code:
    $xpath = "//user/username[contains(.,'a') or ('a'='a')]/../*[('1'='1')]";
    Ce code est un peu plus complexe que le précédent, je vais donc le décortiquer pour que vous compreniez mieux.

    La première étape est de valider la contrainte due à la fonction contains. Ce que nous avons vu juste avant.

    La deuxième étape permet de changer le chemin de recherche dans le fichier XML. Nous mettons un crochet « ] » pour terminer le prédicat sur les éléments « username », nous mettons un « / » pour repartir dans l’arborescence, puis « ../ » pour remonter dans l’arbre. Comme pour le Directory transversal, vous pouvez en mettre plusieurs pour remonter plus haut dans la structure.

    La troisième étape est de déterminer les éléments que nous voulons récupérer. J’ai mis ici « * » pour dire que je voulais renvoyer tous les éléments, mais nous aurions pu mettre « password » pour ne remonter que les mots de passe.

    La dernière étape est là pour compléter la fin de l’expression. En effet, le code PHP rajoutant la chaine « ')] », il faut rajouter un prédicat simple et toujours vérifié pour ne pas avoir d’erreur dans l’interprétation du XPATH.


    4. Sécurisation
    La faille XPATH étant très similaire à celle du SQL, ses vecteur d’attaque sont les mêmes. Une absence ou insuffisance de contrôle sur les valeurs envoyées par un client. Par conséquent, l’échappement des caractères spéciaux, notamment les simples et doubles quotes, est la méthode préférable pour se prémunir de ce type d’attaque. Vous pouvez également faire des vérifications plus poussées en fonction des données. Par exemple, si une des données est une quantité entière, la présence de lettre et de caractère spéciaux n’est pas permise et renvoi une erreur.

    Le tutoriel est maintenant terminé. J’espère que vous avez eu plaisir à le lire et surtout que vous avez pu le comprendre
    N’hésitez pas si certains passages ne sont pas clairs, que j’édite et améliore le tutoriel. Je suis donc à votre disposition pour répondre aux questions.

    Bonne continuation.
    “ Deux choses sont infinies. L'univers et la stupidité humaine ... et je ne suis pas sûr pour l'univers.”
    -Albert Einstein
Chargement...
X