【第4周】一个被广泛流传的XXE漏洞错误修复方案

  • A+
所属分类:安全文章


现在百度"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。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

在newDocumentBuilder()会方法返回一个DocumentBuilderImpl对象前,会在DocumentBuilderImpl对象初始化时,调用setFeature()方法对DOM解析器的CREATE_ENTITY_REF_NODES_FEATURE(http://apache.org/xml/features/dom/create-entity-ref-nodes) 配置项设置为上一步的expandEntityRef变量的相反值true。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

domParser.setFeature()最终会调用解析器配置对象设置目标配置项的值。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

在XMLParser对象调用reset()方法重置状态时,AbstractDOMParser对象中通过解析器的配置对象获取到CREATE_ENTITY_REF_NODES(http://apache.org/xml/features/dom/create-entity-ref-nodes) 配置项的值true,并将`fCreateEntityRefNodes`属性设置为true。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

在XMLDocumentFragmentScannerImpl.scanDocument()进入START_ELEMENT阶段后,next()方法会对XML中的元素进行扫描。当扫描到文本中的&字符时(识别一般实体),解析器会调用scanEntityReference() 扫描实体引用。最后会调用setupCurrentEntity()创建连接并发起请求,以获取外部实体的内容,这时XXE漏洞将会触发!可以发现程序运行流程,依然会执行到XXE漏洞触发的位置。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

【第4周】一个被广泛流传的XXE漏洞错误修复方案

继续跟踪,AbstractDOMParser.endGeneralEntity()在判断fCreateEntityRefNodesfalse时,实体引用&xxe将会被从DOM树删除,引用的具体内容Test by c0ny1将会在DOM树中展开,替换掉&xxe。此时为true,实体引用节点将保留在DOM树中。这是setExpandEntityReferences方法对XML解析器处理XML最终产生影响的位置。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

最终调用链如下:

【第4周】一个被广泛流传的XXE漏洞错误修复方案

经过以上分析,我们大致了解了setExpandEntityReferences()方法的功能是对解析XML生成的Document文档进行设置,设置为true则展开实体引用到生成的文档中替换掉&xxx的实体引用声明,设置为false则保留实体引用声明的DOM树在生成的文档中。


由于setExpandEntityReferences(false)对Java内置XML解析器的设置起作用前,解析器就已经发起了对外部实体的请求了,故无法防御XXE漏洞!



 0x03 

思考原因



为何setExpandEntityReferences明明无法防御XXE漏洞,但却很多人在使用呢?当我看了官方JDK API文档之后,发现描述过于简单,从字面上理解很容易与方法的实际功能存在偏差。

【第4周】一个被广泛流传的XXE漏洞错误修复方案

初步判断有两个原因:


1. 官方文档的描述太过于模糊,很容易让人产生歧义。如果没有跟踪该方法底层实现很容易对它的实际功能理解错误,从而导致错误使用。


2. 第一批修复的人应该是看了官方JDK文档来编写修复代码的,之后更多的人是直接百度到了一批人的编写的错误修复代码,直接复制粘贴。导致这个错误的修复方案进一步蔓延。



 0x04 

参考文章



【第4周】一个被广泛流传的XXE漏洞错误修复方案




本文始发于微信公众号(回忆飘如雪):【第4周】一个被广泛流传的XXE漏洞错误修复方案

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: