Java代码审计之Struts2-001
字数 1513 2025-08-25 22:59:02
Struts2-001 远程代码执行漏洞分析与复现
漏洞概要
Struts2-001 是一个远程代码执行漏洞,影响版本为 Struts 2.0.0 - Struts 2.0.8。该漏洞源于 Struts2 框架对 OGNL 表达式的递归解析机制存在缺陷,导致攻击者可以构造恶意 OGNL 表达式实现任意代码执行。
环境搭建
所需组件
- Apache Tomcat 8.5.47
- Struts 2.0.8 (可从 http://archive.apache.org/dist/struts/binaries/struts-2.0.8-all.zip 下载)
- 或使用 Vulhub 提供的环境:https://github.com/vulhub/vulhub/tree/master/struts2/s2-001
漏洞原理分析
Struts2 请求处理流程
- HTTP 请求进入 Struts2 框架后,会经过一系列拦截器(Interceptor)处理
- 这些拦截器可以是 Struts2 自带的或用户自定义的
- 在
struts-default.xml文件中定义了默认拦截器栈defaultStack
关键拦截器 - params
params拦截器负责将客户端请求数据设置到值栈(valueStack)中- 后续 JSP 页面中的所有动态数据都将从值栈中获取
漏洞触发流程
- 请求经过
params拦截器处理,将参数存入值栈 - 根据 Action 处理结果返回对应 JSP 视图
- JSP 中的 Struts2 标签(如
<s:textfield>)被处理:- 调用
doStartTag方法 - 设置标签属性到
TextFieldTag对象 - 调用
doEndTag方法
- 调用
doEndTag调用this.component.end方法end方法调用evaluateParams填充动态数据
关键漏洞点
- 当开启 OGNL 表达式支持(
altSyntax)时:- 程序会在属性字段两边添加 OGNL 表达式字符(
%{和}) - 使用
findValue方法从值栈解析表达式
- 程序会在属性字段两边添加 OGNL 表达式字符(
findValue调用translateVariables方法递归解析 OGNL 表达式- 问题在于:
- 初始表达式如
%{username}被解析 - 如果
username的值是另一个 OGNL 表达式(如%{1+1}) - 由于使用
while循环解析,会递归执行表达式 - 导致任意 OGNL 表达式被执行
- 初始表达式如
漏洞复现
测试 Payload
- 基本验证:
%{1+1}
- 执行系统命令(示例启动计算器):
%{(new java.lang.ProcessBuilder(new java.lang.String[]{"deepin-calculator"})).start()}
复现步骤
- 搭建漏洞环境
- 找到存在漏洞的表单页面
- 在表单字段中提交恶意 OGNL 表达式
- 观察表达式执行结果
漏洞修复
官方在 xwork-2.0.4 中修复了此漏洞:
- 添加了对 OGNL 递归解析次数的限制
- 默认情况下仅解析第一层表达式
- 修复代码对比:
- 左图(xwork-2.0.3):无递归限制
- 右图(xwork-2.0.4):添加了最大解析深度控制
防御措施
- 升级到 Struts 2.0.9 或更高版本
- 如果无法立即升级,可考虑:
- 禁用 OGNL 表达式支持
- 实现自定义拦截器过滤恶意 OGNL 表达式
- 对用户输入进行严格过滤
总结
Struts2-001 漏洞展示了框架设计中对递归解析缺乏限制可能导致的安全问题。理解该漏洞有助于:
- 深入理解 Struts2 框架的工作机制
- 认识 OGNL 表达式注入的风险
- 在代码审计中关注类似递归解析的场景
- 提高对输入验证重要性的认识