
前言
近期,Apache Struts2框架被披露存在一个编号为S2-069的安全漏洞,其本质是一个XML外部实体注入(XXE)漏洞。本文将对这一漏洞进行深入的技术分析,并带领大家完成漏洞环境的搭建与复现。
技术研究过程
该漏洞的根源在于Apache Struts2框架的XWork-Core组件对XML解析器的安全配置存在疏漏。攻击者能够构造恶意的XML数据并发往受影响的Struts2应用,从而触发XML外部实体注入攻击。成功的利用可能导致敏感数据被窃取、实现服务端请求伪造(SSRF)或引发拒绝服务等严重后果。
影响版本:
- Struts 2.0.0 - 2.3.37 (EOL)
- Struts 2.5.0 - 2.5.33 (EOL)
- Struts 6.0.0 - 6.1.0
漏洞分析过程
通过对Struts2 6.0.3版本与6.1.1版本的源码进行比对,我们可以清晰地看到修复点。如下图所示,在com.opensymphony.xwork2.util.DomHelper.parse类中,修复后的代码增加了关键的安全配置。

修复的核心在于以下两行代码,它们被添加到了SAXParserFactory的初始化过程中:
第一行代码禁用了外部通用实体解析。这意味着类似 <!ENTITY xxe SYSTEM "file:///etc/passwd"> 这样的外部实体引用将不会被处理,从根本上阻断了利用外部文件实体进行数据窃取的常见XXE攻击路径。
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
第二行代码则禁用了外部参数实体。参数实体在DTD内部使用,常用于构造更复杂的XXE攻击链,例如加载远程DTD来绕过某些过滤限制。关闭此特性可以防御更多高级的XXE变种。
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
此外,在另一个类 XSLTResult.java 中也发现了针对XXE的修复,如下图所示:

这里的修复通过设置TransformerFactory的属性来实现:
将 XMLConstants.ACCESS_EXTERNAL_DTD 属性设置为空字符串,意味着完全禁止Transformer访问任何外部的DTD文档。
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
同样,将 XMLConstants.ACCESS_EXTERNAL_STYLESHEET 属性设置为空字符串,旨在禁止访问任何外部的XSLT样式表,消除了通过样式表引入外部实体的风险。
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
漏洞复现过程
为了验证漏洞,我们首先使用IntelliJ IDEA搭建一个简单的测试环境。创建一个存在漏洞的Action类,其关键部分代码如下,它直接使用未安全配置的解析器处理用户传入的XML输入流。

使用网络上公开的EXP构造Payload进行测试。如下图所示,我们发送一个包含指向C:\windows\win.ini文件的外部实体引用的XML数据包,服务器成功解析并返回了文件内容,证实漏洞存在且可利用。

漏洞验证方法
在实际的安全测试中,我们通常需要快速判断目标是否存在此漏洞。一种直接的方法是尝试读取系统文件,如/etc/passwd或C:\windows\win.ini,并通过回显判断。

然而,并非所有XML解析场景都有内容回显。此时,无回显的验证方式就显得尤为重要。我们可以利用DNSLog技术,构造一个指向我们可控域名的外部实体。如果漏洞存在,目标服务器在解析XML时会尝试进行DNS查询,从而在DNSLog平台上留下记录,以此作为漏洞存在的证据。

总结
S2-069漏洞再次提醒我们,对于Struts2这类广泛使用的老牌框架,即使已发布多年,其历史版本中仍可能潜藏着未被广泛认知的安全风险。开发者在处理用户可控的XML数据时,必须对解析器进行严格的安全配置,禁用外部实体解析是基本原则。对于安全研究人员而言,掌握代码比对、环境搭建、多手段验证等技能,是进行有效漏洞分析与复现的关键。如果你对Web安全与漏洞挖掘有更多兴趣,欢迎到云栈社区的相关板块与大家交流探讨。