XML External Entity – Beyond /etc/passwd (For Fun & Profit)
Last week I was asked twice in one day if I knew what XML External Entity (XXE) Vulnerabilities were. Maybe they are making a comeback in mainstream security buzz or sales jargon, I have no idea. (Often buzz-words propagated by the media or sales engineers become the driving factor for many of the conversations I have.)
There are great articles out there already that explain the details of XXE, if you need clarification on the vulnerability, check out the GIAC Gold Paper by Carrie Roberts here. Until recently, XXE was never something I wouldn’t get excited about. Usually, I would just leverage the vulnerability to read files from the local system. Some bugs I drool for and hope to find, XXE was never one of them.
So I began looking into the latest XXE vulns on exploit-db, watching talks on YouTube, and reading papers\blogs\articles on XXE. The OWASP documentation is a good place to start https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing. The bit that caught my attention in the OWASP information is “an attacker may use this trusted application to pivot to other internal systems, possibly disclosing other internal content via http(s) requests or launching a CSRF attack to any unprotected internal services.”
Now We’re Talking, Let’s See What We Can Do!
The great thing about many of the XML parser implementations available today is that they allow for XXE exploitation by default.
Take the following PHP script, it parses XML sent to it and echoes it back to the user. I named mine NEW_XXE.php and stuck it in the CUSTOM directory under my web root. This “application” does absolutely nothing, but who cares, we want to mess with the parser itself.
I install this PHP script on WEBSVR01.
<?php $xmlfile = file_get_contents('php://input'); $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); $xml = simplexml_import_dom($dom); $stuff = $xml->stuff; $str = "$stuff \n"; echo $str; ?>
You can throw the above script into your PHP server (make sure you install php-xml), if you want to create this scenario in a lab.
Now create an xml file to send as a request to the server with the following content. I named mine “send.txt” and send it from WEBSVR01 to localhost, to make sure everything works as expected locally.
<xml> <stuff>This is my stuff</stuff> </xml>
Put whatever you want in stuff and send it to WEBSVR01 aka localhost like so.
See the echoed response.
So the “application” is up and running. Good. Now we can mess with the parser.
Let’s call some External Entities
Modify “send.txt” to be the following.
This is a typical XXE attack against a Linux System and is a good way to prove the vulnerability exists. If everything is working correctly you should get a dump of “/etc/passwd”
From WEBSVR01 send it again to localhost.
Another very useful thing you can do with XXE is create HTTP requests.
Start the python SimpleHTTPServer on port 8888 on WEBSVR01 and let’s see what happens.
And on my python http server.
Cool we can send http requests.
From a remote system I can exploit this vulnerability and get some of the network information. First let me paint the picture, you find this vulnerability on a web server on the internet and you want to use it as a pivot point.
The diagram below lays it all out. I get a web server on 22.214.171.124, that host is really WEBSVR01 behind the NAT/Firewall device. WEBSVR01 has an XXE vulnerability that I want to use to gather information and potentially exploit WEBSRV02. I’m sitting on the open internet, on my Attack PC.
You know it’s an Ubuntu server because you did a proper enumeration. There are a few places you want to look to get the networking information of this server.
First you want to grab “/etc/networking/interfaces”, and if you need more information look in “/proc/net/route” (These values are hex and you may need to convert them if it comes to that).
Let me walk you through it. From my Attack PC (Ubuntu 14 LTS), I create the request file to grab “/etc/network/interfaces” from the vulnerable web server.
On ATTACK PC Edit the file to grab /etc/passwd:
Make the request:
Great! We now know the IP Scheme of the Internal network or DMZ this host is sitting on.
Let’s grab the default page of this server via XXE using its internal IP address 10.0.0.3
NOTE! Some characters will break the XML. So far we have only looked at files or made simple http requests that did not return characters that would break our XML. Since we are using PHP we can base64 encode what is returned. On the ATTACK PC Change your “send.txt” to match the following, adding the following PHP filter.
Now Send The Request
We get a bit of base64 back. Once decoded we have the page contents.
Building an HTTP Scanner!
Putting this all together, I can now scan the internal IP range for web servers .
Of course some Python.
You can get the script on my GitHub here.
From the ATTACK PC, EXECUTE!
Let’s see what the Base64 Decodes as for the data returned from 10.0.0.4
Nice little exploit on exploit-db.com
Since we are getting an index.pl (Perl) file, I’m going to assume CGI is enabled, so this exploit could work. And it works by passing the parameters in a GET request, so we can exploit it through the XXE vulnerability on the external facing host.
After decrypting the Metasploit Module, the request that needs to be sent looks like this URL encoded http request:
Notice I put my IP address in there “126.96.36.199” and the port my Netcat listener will be on. The entire string is an URL encoded reverse Netcat shell without the “-e” support utilizing mknod and a backpipe.
So let’s trigger the exploit on 10.0.0.4 via the XXE Vulnerability.
On the ATTACK PC Create a Netcat listener and Execute!
Looks like a Reverse Shell!
So there you have it. A small tutorial on taking an XML External Entity vulnerability from an external host, and using it to exploit a vulnerability on an internal host. I want to thank BHIS and special thanks to Carrie Roberts for the excellent Gold Paper.
*Robert is a guest poster on our blog. Interested in guest posting? Contact us here.
Join the BHIS Blog Mailing List – get notified when we post new blogs, webcasts, and podcasts.
May 1, 2017 @ 6:24 pm
It’s XXE, not XEE.
May 2, 2017 @ 8:14 am
Whoops! Thanks for bringing this to our attention, it’s been updated 🙂