XXE : injection d'entités externes XML
XXE (XML External Entity) est une classe de vulnérabilité qui exploite la fonctionnalité d'entités externes du standard XML. Les entités XML sont des raccourcis : &name; peut être défini pour représenter une chaîne de caractères, mais aussi une ressource externe (fichier local ou URL distante). Quand un parseur XML résout ces entités externes sans restriction, l'attaquant peut définir des entités qui lisent des fichiers sensibles ou font des requêtes réseau.
Lecture de fichiers locaux
Payload XXE : lecture de /etc/passwd
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>
<!-- L'application retourne le contenu de /etc/passwd
dans la réponse si elle affiche le contenu de <data> -->
En lecture directe ("in-band"), le contenu du fichier est retourné dans la réponse de l'application. Quand la réponse ne contient pas directement la valeur ("out-of-band"), l'attaquant peut exfiltrer les données via une requête DNS ou HTTP vers un serveur qu'il contrôle, en définissant une entité qui charge une URL externe contenant les données du fichier.
XXE comme vecteur SSRF
En remplaçant file:// par http://, XXE devient une SSRF. L'attaquant peut faire des requêtes vers des services internes, le service de métadonnées cloud, ou scanner le réseau interne depuis le serveur.
Déni de service par expansion d'entités (Billion Laughs)
Attaque Billion Laughs : expansion exponentielle
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<!-- Résultat : 10^9 "lol" en mémoire. Le parseur s'effondre. -->
Prévention
La correction est simple : désactiver le traitement des entités externes dans le parseur XML. C'est une option de configuration disponible dans tous les parseurs modernes. Si les entités internes sont nécessaires, elles peuvent être conservées en désactivant uniquement les entités externes.
Désactivation des entités externes (Java, Python, PHP)
// Java (DocumentBuilderFactory)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
# Python (lxml)
from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
# PHP
libxml_disable_entity_loader(true); // Avant PHP 8.0
// PHP 8.0+ : désactivé par défaut
Si l'application n'a pas besoin de traiter du XML du tout (ou peut basculer vers JSON), c'est la solution la plus sûre : ne pas traiter le XML, ou utiliser un parseur qui ignore les DTDs (Document Type Definitions) par défaut.
Pour aller plus loin
Une question après la lecture ?
Votre application traite du XML ? Envoyez un message.
Ou réservez directement un cadrage de 30 minutes
Réserver un appel →