JAVA常见的XXE漏洞写法和防御

13 篇文章 0 订阅
11 篇文章 0 订阅

说明

貌似最近经常看到有Java项目爆出XXE的漏洞并且带有CVE,包括Spring-data-XMLBean XXE漏洞JavaMelody组件XXE漏洞解析Apache OFBiz漏洞。微信支付SDK的XXE漏洞。本质上xxe的漏洞都是因为对xml解析时允许引用外部实体,从而导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。

apache OFBiz中的XML解析是由UtilXml.java中readXmlDocument()完成的:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public static Document readXmlDocument(InputStream is, boolean validate, String docDescription)

throws SAXException, ParserConfigurationException, java.io.IOException {

//omit java code

 

Document document = null;

/* Standard JAXP (mostly), but doesn't seem to be doing XML Schema validation, so making sure that is on... */

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setValidating(validate);

factory.setNamespaceAware(true);

 

factory.setAttribute("http://xml.org/sax/features/validation", validate);

factory.setAttribute("http://apache.org/xml/features/validation/schema", validate);

 

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);

factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

factory.setXIncludeAware(false);

factory.setExpandEntityReferences(false);

 

我们就有理由相信XXE漏洞是由DocumentBuilderFactory设置不当操作造成的,当然我们现在看到的是修改之后的版本;

JavaMelody中是由PayloadNameRequestWrapper.java中的parseSoapMethodName来解析XML。

1

2

3

4

5

6

7

8

9

10

11

12

private static String parseSoapMethodName(InputStream stream, String charEncoding) {

    try {

        // newInstance() et pas newFactory() pour java 1.5 (issue 367)

        final XMLInputFactory factory = XMLInputFactory.newInstance();

        final XMLStreamReader xmlReader;

        if (charEncoding != null) {

            xmlReader = factory.createXMLStreamReader(stream, charEncoding);

        } else {

            xmlReader = factory.createXMLStreamReader(stream);

        }

        // omit java code

}

 

JAVA常见的XXE漏洞写法和防御

发表于 2018-10-23

说明

貌似最近经常看到有Java项目爆出XXE的漏洞并且带有CVE,包括Spring-data-XMLBean XXE漏洞JavaMelody组件XXE漏洞解析Apache OFBiz漏洞。微信支付SDK的XXE漏洞。本质上xxe的漏洞都是因为对xml解析时允许引用外部实体,从而导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。

apache OFBiz中的XML解析是由UtilXml.java中readXmlDocument()完成的:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public static Document readXmlDocument(InputStream is, boolean validate, String docDescription)

throws SAXException, ParserConfigurationException, java.io.IOException {

//omit java code

 

Document document = null;

/* Standard JAXP (mostly), but doesn't seem to be doing XML Schema validation, so making sure that is on... */

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setValidating(validate);

factory.setNamespaceAware(true);

 

factory.setAttribute("http://xml.org/sax/features/validation", validate);

factory.setAttribute("http://apache.org/xml/features/validation/schema", validate);

 

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);

factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

factory.setXIncludeAware(false);

factory.setExpandEntityReferences(false);

 

 

我们就有理由相信XXE漏洞是由DocumentBuilderFactory设置不当操作造成的,当然我们现在看到的是修改之后的版本;

JavaMelody中是由PayloadNameRequestWrapper.java中的parseSoapMethodName来解析XML。

 

1

2

3

4

5

6

7

8

9

10

11

12

private static String parseSoapMethodName(InputStream stream, String charEncoding) {

    try {

        // newInstance() et pas newFactory() pour java 1.5 (issue 367)

        final XMLInputFactory factory = XMLInputFactory.newInstance();

        final XMLStreamReader xmlReader;

        if (charEncoding != null) {

            xmlReader = factory.createXMLStreamReader(stream, charEncoding);

        } else {

            xmlReader = factory.createXMLStreamReader(stream);

        }

        // omit java code

}

 

 

根据JavaMelody组件XXE漏洞解析的分析,是由于xmlReader没有限制外部查询导致的XXE漏洞。

同样地,微信支付SDK的XXE漏洞和Spring-data-XMLBean XXE漏洞都是是使用了DocumentBuilderFactory没有限制外部查询而导致XXE。

从这些例子中,可以发现在Java中其实存在着非常多的解析XML的库,同时由于在Java应用中会大量地使用到XML,因此就会出现使用不同的库对XML继续解析,而编写这些代码的研发人员并没有相关的安全背景,所以就导致了层出不穷地Java XXE漏洞。

不同库的Java XXE漏洞

我们测试的Payload很简单:

1

2

3

4

5

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE root [

<!ENTITY xxe SYSTEM "dnslog-ip">

]>

<evil>&xxe;</evil>

DocumentBuilderFactory

错误地修复方式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = dbf.newDocumentBuilder();

String FEATURE = null;

FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";

dbf.setFeature(FEATURE, true);

FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";

dbf.setFeature(FEATURE, true);

FEATURE = "http://xml.org/sax/features/external-parameter-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://xml.org/sax/features/external-general-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";

dbf.setFeature(FEATURE, false);

dbf.setXIncludeAware(false);

dbf.setExpandEntityReferences(false);

// 读取xml文件内容

FileInputStream fis = new FileInputStream("path/to/xxexml");

InputSource is = new InputSource(fis);

builder.parse(is);

 

看似设置得很很全面,但是直接仍然会被攻击,原因就是在于DocumentBuilder builder = dbf.newDocumentBuilder();这行代码需要在dbf.setFeature()之后才能够生效;

正确地修复方式
 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

String FEATURE = null;

FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";

dbf.setFeature(FEATURE, true);

FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";

dbf.setFeature(FEATURE, true);

FEATURE = "http://xml.org/sax/features/external-parameter-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://xml.org/sax/features/external-general-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";

dbf.setFeature(FEATURE, false);

dbf.setXIncludeAware(false);

dbf.setExpandEntityReferences(false);

DocumentBuilder builder = dbf.newDocumentBuilder();

// 读取xml文件内容

FileInputStream fis = new FileInputStream("path/to/xxexml");

InputSource is = new InputSource(fis);

Document doc = builder.parse(is);

注意DocumentBuilder builder = dbf.newDocumentBuilder();在两种不同的位置的差异性。

SAXBuilder

这个库貌似使用得不是很多。SAXBuilder如果使用默认配置就会触发XXE漏洞;如下

 

1

2

SAXBuilder builder = new SAXBuilder();

Document doc = builder.build(InputSource);

 

JAVA常见的XXE漏洞写法和防御

发表于 2018-10-23

说明

貌似最近经常看到有Java项目爆出XXE的漏洞并且带有CVE,包括Spring-data-XMLBean XXE漏洞JavaMelody组件XXE漏洞解析Apache OFBiz漏洞。微信支付SDK的XXE漏洞。本质上xxe的漏洞都是因为对xml解析时允许引用外部实体,从而导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。

apache OFBiz中的XML解析是由UtilXml.java中readXmlDocument()完成的:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public static Document readXmlDocument(InputStream is, boolean validate, String docDescription)

throws SAXException, ParserConfigurationException, java.io.IOException {

//omit java code

 

Document document = null;

/* Standard JAXP (mostly), but doesn't seem to be doing XML Schema validation, so making sure that is on... */

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setValidating(validate);

factory.setNamespaceAware(true);

 

factory.setAttribute("http://xml.org/sax/features/validation", validate);

factory.setAttribute("http://apache.org/xml/features/validation/schema", validate);

 

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);

factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

factory.setXIncludeAware(false);

factory.setExpandEntityReferences(false);

 

 

我们就有理由相信XXE漏洞是由DocumentBuilderFactory设置不当操作造成的,当然我们现在看到的是修改之后的版本;

JavaMelody中是由PayloadNameRequestWrapper.java中的parseSoapMethodName来解析XML。

 

1

2

3

4

5

6

7

8

9

10

11

12

private static String parseSoapMethodName(InputStream stream, String charEncoding) {

    try {

        // newInstance() et pas newFactory() pour java 1.5 (issue 367)

        final XMLInputFactory factory = XMLInputFactory.newInstance();

        final XMLStreamReader xmlReader;

        if (charEncoding != null) {

            xmlReader = factory.createXMLStreamReader(stream, charEncoding);

        } else {

            xmlReader = factory.createXMLStreamReader(stream);

        }

        // omit java code

}

 

 

根据JavaMelody组件XXE漏洞解析的分析,是由于xmlReader没有限制外部查询导致的XXE漏洞。

同样地,微信支付SDK的XXE漏洞和Spring-data-XMLBean XXE漏洞都是是使用了DocumentBuilderFactory没有限制外部查询而导致XXE。

从这些例子中,可以发现在Java中其实存在着非常多的解析XML的库,同时由于在Java应用中会大量地使用到XML,因此就会出现使用不同的库对XML继续解析,而编写这些代码的研发人员并没有相关的安全背景,所以就导致了层出不穷地Java XXE漏洞。

不同库的Java XXE漏洞

我们测试的Payload很简单:

 

1

2

3

4

5

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE root [

<!ENTITY xxe SYSTEM "dnslog-ip">

]>

<evil>&xxe;</evil>

 

 

DocumentBuilderFactory

错误地修复方式

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = dbf.newDocumentBuilder();

String FEATURE = null;

FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";

dbf.setFeature(FEATURE, true);

FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";

dbf.setFeature(FEATURE, true);

FEATURE = "http://xml.org/sax/features/external-parameter-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://xml.org/sax/features/external-general-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";

dbf.setFeature(FEATURE, false);

dbf.setXIncludeAware(false);

dbf.setExpandEntityReferences(false);

// 读取xml文件内容

FileInputStream fis = new FileInputStream("path/to/xxexml");

InputSource is = new InputSource(fis);

builder.parse(is);

 

看似设置得很很全面,但是直接仍然会被攻击,原因就是在于DocumentBuilder builder = dbf.newDocumentBuilder();这行代码需要在dbf.setFeature()之后才能够生效;

正确地修复方式

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

String FEATURE = null;

FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";

dbf.setFeature(FEATURE, true);

FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";

dbf.setFeature(FEATURE, true);

FEATURE = "http://xml.org/sax/features/external-parameter-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://xml.org/sax/features/external-general-entities";

dbf.setFeature(FEATURE, false);

FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";

dbf.setFeature(FEATURE, false);

dbf.setXIncludeAware(false);

dbf.setExpandEntityReferences(false);

DocumentBuilder builder = dbf.newDocumentBuilder();

// 读取xml文件内容

FileInputStream fis = new FileInputStream("path/to/xxexml");

InputSource is = new InputSource(fis);

Document doc = builder.parse(is);

 

注意DocumentBuilder builder = dbf.newDocumentBuilder();在两种不同的位置的差异性。

SAXBuilder

这个库貌似使用得不是很多。SAXBuilder如果使用默认配置就会触发XXE漏洞;如下

 

1

2

SAXBuilder builder = new SAXBuilder();

Document doc = builder.build(InputSource);

 

 

修复方法

方式1

 

1

2

SAXBuilder builder = new SAXBuilder(true);

Document doc = builder.build(InputSource);

 

 

方式2

 

1

2

3

4

5

6

SAXBuilder builder = new SAXBuilder();

builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

builder.setFeature("http://xml.org/sax/features/external-general-entities", false);

builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

Document doc = builder.build(InputSource);

 

 

SAXParserFactory

同样地,在默认配置下就会存在XXE漏洞。

 

1

2

3

SAXParserFactory spf = SAXParserFactory.newInstance();

SAXParser parser = spf.newSAXParser();

parser.parse(InputSource, (HandlerBase) null);

 

 

修复方法

 

1

2

3

4

5

6

7

SAXParserFactory spf = SAXParserFactory.newInstance();

spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

spf.setFeature("http://xml.org/sax/features/external-general-entities", false);

spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

SAXParser parser = spf.newSAXParser();

parser.parse(InputSource, (HandlerBase) null);

 

SAXReader

在默认情况下会出现XXE漏洞。

 

1

2

SAXReader saxReader = new SAXReader();

saxReader.read(InputSource);

 

 

修复方法

 

1

2

3

4

5

6

SAXReader saxReader = new SAXReader();

saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);

saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

saxReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

saxReader.read(InputSource);

 

SAXTransformerFactory

在默认情况下会出现XXE漏洞

 

1

2

3

SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();

StreamSource source = new StreamSource(InputSource);

sf.newTransformerHandler(source);

 

 

但是有趣的是,在默认配置,虽然能够触发XXE漏洞,但是出现运行时会报错;如下所示:
 

 

但是只是存在Web的解析记录。

修复方法

 

1

2

3

4

5

SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();

sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");

sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

StreamSource source = new StreamSource(InputSource);

sf.newTransformerHandler(source);

 

通过跟踪源代码发现,XMLConstants.ACCESS_EXTERNAL_DTD的内容是http://javax.xml.XMLConstants/property/accessExternalDTD,XMLConstants.ACCESS_EXTERNAL_STYLESHEET是http://javax.xml.XMLConstants/property/accessExternalStylesheet

SchemaFactory

在默认情况下也会出现XXE漏洞。

 

1

2

3

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

StreamSource source = new StreamSource(ResourceUtils.getPoc1());

Schema schema = factory.newSchema(InputSource);

 

 

和SAXTransformerFactory虽然在运行时会报错,当时仍然能够触发XXE。

同样也只存在Web的解析记录。

修复方法

 

1

2

3

4

5

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");

factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

StreamSource source = new StreamSource(InputSource);

Schema schema = factory.newSchema(source);

 

和SAXTransformerFactory的修复原理一样就不作说明了。

TransformerFactory

使用默认的解析方法会存在XXE问题。

 

1

2

3

TransformerFactory tf = TransformerFactory.newInstance();

StreamSource source = new StreamSource(InputSource);

tf.newTransformer().transform(source, new DOMResult());

 

 

修复方法

 

1

2

3

4

5

TransformerFactory tf = TransformerFactory.newInstance();

tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");

tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

StreamSource source = new StreamSourceInputSource);

tf.newTransformer().transform(source, new DOMResult());

 

ValidatorSample

使用默认的解析方法会存在XXE问题

 

1

2

3

4

5

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

Schema schema = factory.newSchema();

Validator validator = schema.newValidator();

StreamSource source = new StreamSource(InputSource);

validator.validate(source);

 

 

修复方法

 

1

2

3

4

5

6

7

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

Schema schema = factory.newSchema();

Validator validator = schema.newValidator();

validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");

validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

StreamSource source = new StreamSource(InputSource);

validator.validate(source);

 

XMLReader

使用默认的解析方法会存在XXE问题

 

1

2

XMLReader reader = XMLReaderFactory.createXMLReader();

reader.parse(new InputSource(InputSource));

 

 

修复方法

 

1

2

3

4

5

6

XMLReader reader = XMLReaderFactory.createXMLReader();

reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

reader.setFeature("http://xml.org/sax/features/external-general-entities", false);

reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

reader.parse(new InputSource(InputSource));

 

Unmarshaller

使用默认的解析方法不会存在XXE问题,这也是唯一一个使用默认的解析方法不会存在XXE的一个库。

 

1

2

3

4

5

Class tClass = Some.class;

JAXBContext context = JAXBContext.newInstance(tClass);

Unmarshaller um = context.createUnmarshaller();

Object o = um.unmarshal(ResourceUtils.getPoc1());

tClass.cast(o);

 

 

总结

其实,通过对不同的XML解析库的修复方式可以发现,XXE的防护值需要限制带外实体的注入就可以了,修复方式也简单,需要设置几个选项为发false即可,可能少许的几个库可能还需要设置一些其他的配置,但是都是类似的。

总体来说修复方式都是通过设置feature的方式来防御XXE。两种方法分别是:

 

1

2

3

4

"http://apache.org/xml/features/disallow-doctype-decl", true 

"http://apache.org/xml/features/nonvalidating/load-external-dtd", false

"http://xml.org/sax/features/external-general-entities", false

"http://xml.org/sax/features/external-parameter-entities", false

 

 

配置如上。

另外一种是:

 

1

2

XMLConstants.ACCESS_EXTERNAL_DTD, ""

XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""

 

 

本质上XXE的问题就是一个配置不当的问题,即容易发现也容易防御,但是前提是需要知道有这个漏洞,这也是就是很多开发人员因为不知道XXE最终写出了含有漏洞的代码。

以上。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值