现在百度"XXE漏洞修复",搜索到的Java语言修复方案大部分如下:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
经过实际的测试发现setExpandEntityReferences(false)根本无法防御XXE漏洞!不禁思考到两个问题:
1. setExpandEntityReferences为何无法防御XXE?
2. 为何一个无法防御的方案,却广为流传?
上一周我们深入Java内置XML解析器中,研究XXE漏洞的深层原理。这周我们在这个基础上,进一步弄清以上两个问题。
0x01
测试代码
1package me.gv7.javaxxe;
2
3import org.w3c.dom.Document;
4import org.xml.sax.SAXException;
5import javax.xml.parsers.*;
6import java.io.ByteArrayInputStream;
7import java.io.InputStream;
8
9public class DOMXXETest02 {
10 public static void main(String[] args) throws ParserConfigurationException,SAXException,Exception{
11 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
12 dbf.setExpandEntityReferences(false);
13 DocumentBuilder db = dbf.newDocumentBuilder();
14 String str = "<!DOCTYPE doc [ n" +
15 "<!ENTITY xxe SYSTEM "http://127.0.0.1:1664/test.dtd">n" +
16 "]><doc>&xxe;</doc>";
17 InputStream is = new ByteArrayInputStream(str.getBytes());
18 Document doc = db.parse(is);
19 System.out.println(doc.getElementsByTagName("doc"));
20 }
21}
test.dtd
test by c0ny1
0x02
原理分析
我们在dbf.setExpandEntityReferences(false);打断点开始分析!
setExpandEntityReferences(false)会将DocumentBuilderFactory对象中的expandEntityRef属性默认值true修改为false。
在newDocumentBuilder()会方法返回一个DocumentBuilderImpl对象前,会在DocumentBuilderImpl对象初始化时,调用setFeature()方法对DOM解析器的CREATE_ENTITY_REF_NODES_FEATURE
(http://apache.org/xml/features/dom/create-entity-ref-nodes) 配置项设置为上一步的expandEntityRef变量的相反值true。
domParser.setFeature()最终会调用解析器配置对象设置目标配置项的值。
在XMLParser对象调用reset()方法重置状态时,AbstractDOMParser对象中通过解析器的配置对象获取到CREATE_ENTITY_REF_NODES(http://apache.org/xml/features/dom/create-entity-ref-nodes) 配置项的值true,并将`fCreateEntityRefNodes`属性设置为true。
在XMLDocumentFragmentScannerImpl.scanDocument()进入START_ELEMENT
阶段后,next()方法会对XML中的元素进行扫描。当扫描到文本中的&
字符时(识别一般实体),解析器会调用scanEntityReference() 扫描实体引用。最后会调用setupCurrentEntity()创建连接并发起请求,以获取外部实体的内容,这时XXE漏洞将会触发!可以发现程序运行流程,依然会执行到XXE漏洞触发的位置。
继续跟踪,AbstractDOMParser.endGeneralEntity()
在判断fCreateEntityRefNodes
为false
时,实体引用&xxe将会被从DOM树删除,引用的具体内容Test by c0ny1
将会在DOM树中展开,替换掉&xxe
。此时为true
,实体引用节点将保留在DOM树中。这是setExpandEntityReferences方法对XML解析器处理XML最终产生影响的位置。
最终调用链如下:
经过以上分析,我们大致了解了setExpandEntityReferences()方法的功能是对解析XML生成的Document文档进行设置,设置为true则展开实体引用到生成的文档中替换掉&xxx
的实体引用声明,设置为false则保留实体引用声明的DOM树在生成的文档中。
由于setExpandEntityReferences(false)对Java内置XML解析器的设置起作用前,解析器就已经发起了对外部实体的请求了,故无法防御XXE漏洞!
0x03
思考原因
为何setExpandEntityReferences明明无法防御XXE漏洞,但却很多人在使用呢?当我看了官方JDK API文档之后,发现描述过于简单,从字面上理解很容易与方法的实际功能存在偏差。
初步判断有两个原因:
1. 官方文档的描述太过于模糊,很容易让人产生歧义。如果没有跟踪该方法底层实现很容易对它的实际功能理解错误,从而导致错误使用。
2. 第一批修复的人应该是看了官方JDK文档来编写修复代码的,之后更多的人是直接百度到了一批人的编写的错误修复代码,直接复制粘贴。导致这个错误的修复方案进一步蔓延。
0x04
参考文章
本文始发于微信公众号(回忆飘如雪):【第4周】一个被广泛流传的XXE漏洞错误修复方案
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论