本文主要介绍代码注入攻击的一种特殊类型:XPath 盲注。
如果您不熟悉 XPath 1.0 或需要了解基础知识,请查看 W3 Schools XPath 教程。您还可以在 developerWorks 上找到大量的关于在各种语言环境中使用 XPath 的文章。本文使用的示例主要针对 XPath 1.0,但是也可用于 XPath 2.0。XPath 2.0 实际上增加了您可能遇到的问题。
本文还提供了用于处理 Java JDK 5.0 的 Java 代码示例。同时本文的概念和主题是跨平台的,如果您的应用程序使用 XPath 获取特殊的代码示例,那么您必须使用 JDK 5.0。
注入代码的目的通常是绕过或修改程序的最初目标功能。如果被绕过的功能涉及系统安全,那么结果可能是灾难性的。
快速浏览任何相关 Web 站点(比如 Web Application Security Consortium 或 Security Focus)都会显示很多使用某种形式的代码注入进行的攻击,从 JavaScript 到 SQL 注入再到其他形式的代码注入攻击。最近开始出现的一种威胁是 XPath 盲注攻击。这种攻击的运作跟 SQL 盲注攻击几乎完全相似,与 SQL 注入攻击不同的是,几乎没什么人了解 XPath 盲注攻击或对其进行预防。与 SQL 注入攻击类似,如果使用最佳实践开发安全的应用程序,通常可以轻松地处理该威胁。
例如,如果您的 Web 站点需要身份验证,那么您可能拥有一个 users 表,其中包含惟一 ID、登录名、密码,也许还有一些其他信息,比如角色。从 users 表中检索用户的 SQL 查询可能类似于清单 1。
清单 1. 从 users 表中检索用户的 SQL 查询
Select * from users where loginID=’foo’ and password=’bar’
在这个查询中,用户必须提供 loginID 和 password 作为输入。
如果攻击者在 loginID 字段中输入:’ or 1=1
则形成的查询将类似清单 2。并在 password 中输入:’ or 1=1
清单 2. 从攻击者输入形成的查询
Select * from users where loginID = ’’ or 1=1 and password=’ ’ or 1=1
这个条件会一直匹配,因此攻击者可以进入系统。
XPath 注入的原理大体类似。但是,假设您拥有的不是一个 users 表,而是一个 XML 文件,其中包含了如清单 3 所示的用户信息。
清单 3. user.xml
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user>
<firstname>Ben</firstname>
<lastname>Elmore</lastname>
<loginID>abc</loginID>
<password>test123</password>
</user>
<user>
<firstname>Shlomy</firstname>
<lastname>Gantz</lastname>
<loginID>xyz</loginID>
<password>123test</password>
</user>
<user>
<firstname>Jeghis</firstname>
<lastname>Katz</lastname>
<loginID>mrj</loginID>
<password>jk2468</password>
</user>
<user>
<firstname>Darien</firstname>
<lastname>Heap</lastname>
<loginID>drano</loginID>
<password>2mne8s</password>
</user>
</users>
在 XPath 中,类似于 SQL 查询的语句如清单 4 所示。
清单 4. 匹配 SQL 查询的 XPath 语句
//users/user[loginID/text()=’abc’ and password/text()=’test123’]
要执行类似的攻击以绕过身份验证,
如果攻击者在 loginID 字段中输入:’ or 1=1
您可能会使用类似清单 5 的方法。并在 password 中输入:’ or 1=1
public boolean doLogin(String loginID, String password)
throws ParserConfigurationException, SAXException,IOException,
XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("users.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//users/user[loginID/text()=’"+loginID+"’
and password/text()=’"+password+"’ ]/firstname/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
//print first names to the console
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());}
if (nodes.getLength() >= 1) {
return true;
}
else{
return false;
}
}
}
如同HTML脚本注入一样,在输出中包含攻击者提供的数据的地方,XML是容易受到攻击的。三种最常见的XML注入攻击是:XML数据注入、可扩展样式表语言转换(Extensible Stylesheet Language Transformation,XSLT)注入和XPath/XQuery 注入。
XML通常用于存储数据,如果用户提供的数据是以XML的方式进行存储,那么对攻击者来说,注入额外的、攻击者可能不能正常控制的XML是有可能的。考虑下述XML,在这个XML中,攻击者仅仅能够控制Attacker Text文本:
<?xmlversion="1.0" encoding="UTF-8"?>
<USER role="guest">Attacker Text</USER>
如果用你的输入来替换Attacker Text,那将会是多么有趣的测试用例呢?如果开发人员不够谨慎的话,他们可能错误地允许XML注入。
如果以User1</USER><USER role=“admin”>User2 作为输入的话,将会产生如下的XML(用户输入的是黑体文本部分):
<?xmlversion="1.0" encoding="UTF-8"?>
<USER role="guest">User1</USER>
<USER role="admin">User2</USER>
如果应用程序读取这个文件,并且决定给每个用户分配何种访问权限的时候,User2将获得管理员权限!
提示 如果你能够在XML文件的某个部分注入数据的话,那么发送相同的元素和属性(这些元素和属性是在以前的XML中出现过的,并且是你所不能访问的)就会很有价值。一些XML解析器会使用最后指定的那些元素/属性的实例,这样,你或许就能够有选择性地覆盖以前的一些值。 |
除了注入数据到XML之外,作为XML注入的结果,使代码运行也是可能的。XSL由XSL转换(XSL Transform,XSLT)、XML路径语言(XML PathLanguage,XPath)表达式和XSL格式化对象(Formatting Object,XSL-FO)组成,并且允许在XML文件中使用样式表。这种样式表能够把已有的XML数据转换成新的XML数据。这种新的XML文档通常以HTML的方式在Web浏览器中展现。在这种情况下,攻击者能够注入数据,而这些数据将使脚本在浏览器中运行。
例如,下述XML是RSS提要(RSS feed)中的一部分,这个XML引用了一个超链接:
<link>AttackerText</link>
为了表示上述XML,应用XSLT将上述XML转换为如下的HTML,并传送给Web浏览器:
<AHREF="Attacker Text">Attacker Text</A>
如果你控制了Attacker Text文本的话,你能够想到一种方法来运行脚本吗?即使程序员对攻击者提供的文本进行了HTML编码,攻击者仍然能够利用脚本协议,通过类似于javascript:alert()的输入来运行脚本。如果这个HTML在一个站点或者一定的范围内表现得与原始RSS提要(RSS feed)不同的话,那么,这就是一种通过XML数据引发的HTML脚本攻击。
重要提示 当测试XML注入的时候,可以试着发送尖括号和引号标志来转义当前的XML属性/标签。当应用程序被正确保护的时候,它就不会让用户提供数据来转 |
XPath和XQuery是能够查询XML文档的语言,类似于结构化查询语言(SQL)。事实上,许多流行的数据库允许利用XPath和XQuery来查询数据库。在许多情况下,攻击者不能够直接访问XML数据,但是,攻击者可以用部分数据来创建XPath和XQuery语句,而这些语句能够用来查询XML。这样,攻击者就能够通过精心构造的输入来注入任意的查询,以此来获得数据,而这些数据在正常情况下是不允许攻击者访问的。
XML文件能够包括信息的不同部分或者区域。有时,只有这些信息中的特定部分才会被暴露给最终用户,例如,下述XML包含了姓名和社会保障号:
<?xmlversion='1.0'?>
<staff>
<author>
<name>Tom Gallagher</name>
<SSN>123-45-6789</SSN>
</author>
<author>
<name>Bryan Jeffries</name>
<SSN>234-56-7890</SSN>
</author>
<author>
<name>Lawrence Landauer</name>
<SSN>012-345-6789</SSN>
</author>
</staff>
这个XML存储在一个Web服务器上,并且是不能够被最终用户直接访问的。在这个服务器上用于查询XML的一个网页是能够被最终用户访问的,而且,只有作者姓名能够通过网页进行显示。利用下述XPath表达式就能够获得XML数据:
//*[contains(name,'Attacker-Data')]/name
Attacker-Data是最终用户指定的数据,正如你所看到的那样,攻击者能够控制部分XPath查询。通过指定数据为x')] | //*| //*[contains(name,'y,攻击者能够获得这个XML文件的完整内容。这种输入构造了如下的XPath表达式:
//*[contains(name,'x')] | //*| //*[contains(name,'y')]/name
注意在上述表达式中,管道符号(|)用于表示或操作,左斜线和一个星号(//*)代表所有节点。上述XPath表达式可能有下述三种情况:
1.任何包含x的姓名
2.任何在这个XML文件中的节点
3.任何包含y的姓名
因为在第二种情况下能够返回所有节点,所以攻击者能够获得这个XML文件的所有数据!
更多信息 关于XPath注入的更多信息,请参见Amit Klien在 |
提示 用于XPath/XQuery注入的概念同样适用于SQL |