Skip to content

Latest commit

 

History

History
59 lines (36 loc) · 4.99 KB

bug-of-fixing-java-xxe.md

File metadata and controls

59 lines (36 loc) · 4.99 KB

Java XXE注入修复问题填坑实录

Category Research Language Vuln Type Timestamp Progress

* 前不久,@图南在分析WxJava的XXE注入漏洞时,发现是由于开发者错误使用了Java官方一个容易被误解的API,导致之前的修复方案失效。我和南哥交流之后,经过简单的跟踪分析,发现归根结底是Feature的问题,所以就带大家一起来填填这个坑吧。请在阅读本文之前好好的把南哥的文章看一遍,其中涉及到的内容我都不会再占篇幅描述了。

关于DocumentBuilderFactory

在我之前的《XXE注入漏洞概述》一文中,以dom4j的SAXParser为例简单分析了它对XML文档的解析过程,虽然DocumentBuilderFactory使用的是DOMParser,但是很荣幸,它俩都会调用XMLDocumentFragmentScannerImpl.scanDocument()扫描XML文档。而且OWASP XXE Prevention Cheat Sheet项目中也表示它们的修复方案是一致的:

DocumentBuilderFactory, SAXParserFactory and DOM4J XML Parsers can be configured using the same techniques to protect them against XXE.

所以我们在这稍微简化一下分析过程,不再描述DocumentBuilderFactory的完整解析过程,为大家减减负,直接挑重点说。

标准的DISALLOW_DOCTYPE_DECL_FEATURE

这应该是OWASP最推荐的防御方案了,它与LOAD_EXTERNAL_DTD一起在XMLDocumentScannerImpl中被组成为一组RECOGNIZED_FEATURES,主要过程如下:

  • DocumentBuilderFactory.setFeature()http://apache.org/xml/features/disallow-doctype-decl设置为true时,DOMParser会改变内部fConfiguration变量中相应键的值,以及XMLNSDocumentScannerImplfDisallowDoctype变量的值
  • 在调用DOMParser.parse()时,将XML11ConfigurationXMLDocumentScannerImplfDisallowDoctype也重置为true
  • XMLDocumentFragmentScannerImpl.scanDocument()PrologDriver.next()依次扫描到<!字符后进入SCANNER_STATE_DOCTYPE阶段,该阶段第一件事就是判断fDisallowDoctype的值,如果为true,则直接报告异常信息中断扫描

由此可知,为什么OWASP会这样描述这个方案:

This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented

被误解的setExpandEntityReferences()

这次我们先看OWASP对它的描述:

If for some reason support for inline DOCTYPEs are a requirement, then ensure the entity settings are disabled and beware that SSRF attacks and denial of service attacks are a risk.

简单的说,如果你需要支持内联DOCTYPE,可以使用setExpandEntityReferences(),但要注意SSRF和DoS风险。

那么我们就来分析一下它为什么没有效果:

  • DocumentBuilderFactory.setExpandEntityReferences()传入false会改变DocumentBuilderFactoryImplexpandEntityRef变量的值 (默认为true
  • DocumentBuilderFactory.newDocumentBuilder()创建DocumentBuilderImpl时,会根据expandEntityRef相反值 改变fConfigurationhttp://apache.org/xml/features/dom/create-entity-ref-nodes的值
  • XMLParser.reset()时,AbstractDOMParserfCreateEntityRefNodes变量也被重置为true
  • XMLDocumentFragmentScannerImpl.scanDocument()时,调用scanDoctypeDecl()扫描DOCTYPE,之后交给DTDDriver.next()处理实体声明
  • 当进入START_ELEMENT阶段后,startEntity()会调用scanEntityReference()扫描并解析实体引用&xxe;,而在endEntity()判断fCreateEntityRefNodesfalse时,将会移除掉该节点

由此可知,setExpandEntityReferences()的意思其实是实体引用的值解析后,是否仍在Dom树中保留其原始的表示引用的节点。设置为false的不展开代表保留,则会创建一个对应节点存放在Dom树中。

因此,如果是DTD扫描阶段的SSRF之类的攻击,无论setExpandEntityReferences()传入何值,都是不起任何防御作用的。

说在最后的话

在和南哥一起填这个坑的时候,我们发现网络上还是有不少关于XXE攻防相关的文章的修复建议中只提到了setExpandEntityReferences(false)这个方案,有被Java官方误导过的同学都赶紧更正一下吧。

参考

  1. 修不好的洞,JDK的坑——从WxJava XXE注入漏洞中发现了一个对JDK的误会
  2. OWASP XXE Prevention Cheat Sheet