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 请求处理流程

  1. HTTP 请求进入 Struts2 框架后,会经过一系列拦截器(Interceptor)处理
  2. 这些拦截器可以是 Struts2 自带的或用户自定义的
  3. struts-default.xml 文件中定义了默认拦截器栈 defaultStack

关键拦截器 - params

  • params 拦截器负责将客户端请求数据设置到值栈(valueStack)中
  • 后续 JSP 页面中的所有动态数据都将从值栈中获取

漏洞触发流程

  1. 请求经过 params 拦截器处理,将参数存入值栈
  2. 根据 Action 处理结果返回对应 JSP 视图
  3. JSP 中的 Struts2 标签(如 <s:textfield>)被处理:
    • 调用 doStartTag 方法
    • 设置标签属性到 TextFieldTag 对象
    • 调用 doEndTag 方法
  4. doEndTag 调用 this.component.end 方法
  5. end 方法调用 evaluateParams 填充动态数据

关键漏洞点

  1. 当开启 OGNL 表达式支持(altSyntax)时:
    • 程序会在属性字段两边添加 OGNL 表达式字符(%{})
    • 使用 findValue 方法从值栈解析表达式
  2. findValue 调用 translateVariables 方法递归解析 OGNL 表达式
  3. 问题在于:
    • 初始表达式如 %{username} 被解析
    • 如果 username 的值是另一个 OGNL 表达式(如 %{1+1})
    • 由于使用 while 循环解析,会递归执行表达式
    • 导致任意 OGNL 表达式被执行

漏洞复现

测试 Payload

  1. 基本验证:
%{1+1}
  1. 执行系统命令(示例启动计算器):
%{(new java.lang.ProcessBuilder(new java.lang.String[]{"deepin-calculator"})).start()}

复现步骤

  1. 搭建漏洞环境
  2. 找到存在漏洞的表单页面
  3. 在表单字段中提交恶意 OGNL 表达式
  4. 观察表达式执行结果

漏洞修复

官方在 xwork-2.0.4 中修复了此漏洞:

  1. 添加了对 OGNL 递归解析次数的限制
  2. 默认情况下仅解析第一层表达式
  3. 修复代码对比:
    • 左图(xwork-2.0.3):无递归限制
    • 右图(xwork-2.0.4):添加了最大解析深度控制

防御措施

  1. 升级到 Struts 2.0.9 或更高版本
  2. 如果无法立即升级,可考虑:
    • 禁用 OGNL 表达式支持
    • 实现自定义拦截器过滤恶意 OGNL 表达式
    • 对用户输入进行严格过滤

总结

Struts2-001 漏洞展示了框架设计中对递归解析缺乏限制可能导致的安全问题。理解该漏洞有助于:

  1. 深入理解 Struts2 框架的工作机制
  2. 认识 OGNL 表达式注入的风险
  3. 在代码审计中关注类似递归解析的场景
  4. 提高对输入验证重要性的认识
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 方法从值栈解析表达式 findValue 调用 translateVariables 方法递归解析 OGNL 表达式 问题在于: 初始表达式如 %{username} 被解析 如果 username 的值是另一个 OGNL 表达式(如 %{1+1} ) 由于使用 while 循环解析,会递归执行表达式 导致任意 OGNL 表达式被执行 漏洞复现 测试 Payload 基本验证: 执行系统命令(示例启动计算器): 复现步骤 搭建漏洞环境 找到存在漏洞的表单页面 在表单字段中提交恶意 OGNL 表达式 观察表达式执行结果 漏洞修复 官方在 xwork-2.0.4 中修复了此漏洞: 添加了对 OGNL 递归解析次数的限制 默认情况下仅解析第一层表达式 修复代码对比: 左图(xwork-2.0.3):无递归限制 右图(xwork-2.0.4):添加了最大解析深度控制 防御措施 升级到 Struts 2.0.9 或更高版本 如果无法立即升级,可考虑: 禁用 OGNL 表达式支持 实现自定义拦截器过滤恶意 OGNL 表达式 对用户输入进行严格过滤 总结 Struts2-001 漏洞展示了框架设计中对递归解析缺乏限制可能导致的安全问题。理解该漏洞有助于: 深入理解 Struts2 框架的工作机制 认识 OGNL 表达式注入的风险 在代码审计中关注类似递归解析的场景 提高对输入验证重要性的认识