XML External Entities (XXE)
Injecting Entities into XML data to read local files and exfiltrate data
Last updated
Injecting Entities into XML data to read local files and exfiltrate data
Last updated
Extensible Markup Language (XML) is a common data format for defining structures of data that can be nested. The basics are very simple, HTML is basically XML:
It also allows variables called "entities" to be defined and used throughout the document. These are defined in the Document Type Definition (DTD) using a <!ENTITY
tag. After that, they can be used anywhere in the document using the &[name];
syntax:
This becomes more dangerous when we introduce External Entities. These can reference local files or remote URLs:
These become exploitable when an attacker can inject such entities into a document that will be parsed by the server, and then the result is returned in the response. You could easily read a local file like this, or make any GET request by the server (SSRF).
In some cases, the document you send to the server is not directly returned back to you, only parsed by the server. All hope is not lost, as there are still various different techniques to make it exploitable.
These can be easily detected with out-of-band detection. Tools like interactsh-client
can set up a domain that listens for DNS and HTTP requests, and you can send this domain as an external entity to see if a callback happens:
The goal of most XXE injections is to exfiltrate a local file. Using entities, we can load a file into a variable, and we can make a DNS/HTTP request to any fixed URL. But we can combine the two with External DTDs, which allow the nesting of entities using special "parameter entities". You can recognize these by the %
percentage sign during definition and are used with the %[name];
syntax.
This allows us to define a file
entity, and then put this entity into the URL of another entity. Once these are used anywhere in the document, the contents of the file are put in the URL and the request is made:
The catch is that External DTDs need to be, well, external. This means they cannot be inside of your initial payload and must be fetched from a local file or a remote URL. An attacker can host the file above, and then create the XXE injection attack with the following payload:
A server might be hardened so that it cannot make random outgoing connections to your attacker's website, either to fetch the External DTD or to exfiltrate the file contents. In this case, two new techniques can be combined to still exfiltrate local files.
An application might return details about an error when something goes wrong during the parsing of the XML document. One such error would be if it cannot find the local file specified in the entity. We can abuse this by defining a %file;
entity again, and then using the file contents in the path of another entity, showing those contents in an error message:
Now you might be thinking, how do we load that external entity if outgoing connections are blocked? And this is where the second technique comes in.
On many systems, there are existing XML DTDs that can be repurposed by us attackers to do something similar to what you see above. One simple example is the
/usr/share/xml/fontconfig/fonts.dtd
file with the following content:
The danger here is that an attacker can define this %expr;
variable before it is defined here, and only the first definition will be used. From here, the attacker can escape the context using )>
to add their own entities as if it were an external DTD that they control:
The payload needed will depend on what variables you can overwrite, and the context they are in. Template payloads on 5 different example contexts can be found here:
Here are a few more paths where you might find an existing exploitable DTD:
This technique will allow you to again get the file contents in the error message, without needing any outgoing connection to your server.