XML External Entity Processing

XML External Entity Processing, or XXE, is a vulnerability where an attacker can abuse the XML 1.0 specification for processing XML Entities to have a server include local or remote data when processing XML.

The XML specification defines a way to specify external entities, which are pieces of data that should be substituted into the XML document. The external entities are often references to a URI, and the parser is expected to interpret the URI, retrieve the data, and substitute it into the XML during parsing. Valid URIs can include file://, http://, and other stream handlers enabled on the server. Many XML libraries follow the specification and by default, process these external entities when encountered in an XML file. As a result, the XML file can include sensitive local files to which the webserver has read access, open a network connection to internal IP addresses, and possibly execute arbitrary code on the server.

In PHP, several XML processing libraries use the libxml2 library for actually parsing the XML, which by default resolves external entities unless specifically disabled. Unfortunately, the way that libxml2 implements the disabling, the library is crippled when external entities are disabled, and functions that would otherwise be safe cause an exception in the entire parsing. As a result, MediaWiki cannot disable external entities during the initialization process, but must rely on developers to disable them while using certain functions.

Vulnerable Functions

edit
  • XMLReader::read()
  • DOMDocument::loadXML()
  • DOMDocument::loadHTML()
  • simplexml_load_string()

Prevention

edit

When using one of these functions, please follow a patern like:

$dom = new DOMDocument();
$oldValue = libxml_disable_entity_loader( true );
$dom->loadXML( $xml );
libxml_disable_entity_loader( $oldValue );


$reader = new XMLReader();
$reader->XML( $xml );
$oldValue = libxml_disable_entity_loader( true );
while ( $reader->read() ) {
    ...
}
libxml_disable_entity_loader( $oldValue );


$oldValue = libxml_disable_entity_loader( true );
simplexml_load_string( $xml );
libxml_disable_entity_loader( $oldValue );
edit