struts2反序列化漏洞
作者:休闲 来源:焦点 浏览: 【大 中 小】 发布时间:2026-10-17 06:11:43 评论数:
2013年7月,反序Apache Struts2的列化漏洞一个漏洞让整个互联网炸了锅。当时我还在做渗透测试,反序客户半夜打电话说服务器被上传了webshell,列化漏洞排查一圈发现入口就是反序一个普通的表单提交页面。问题出在Struts2处理请求参数的列化漏洞方式上——它把用户输入的参数名当成了OGNL表达式来执行。
这事的反序本质得从Struts2的架构说起。Struts2的列化漏洞核心是Action,每个HTTP请求都会被映射到某个Action类的反序方法上。为了把请求参数自动填充到Action的列化漏洞属性里,Struts2用了一套叫ValueStack的反序机制。ValueStack说白了就是列化漏洞个数据栈,里面存着Action对象、反序请求参数、列化漏洞会话数据等等。反序当框架解析参数名时,它会通过OGNL(Object-Graph Navigation Language)来定位ValueStack里的对象。问题就在这:OGNL功能太强了,不光能读属性,还能调用方法、执行静态代码。
攻击者构造一个参数名,比如%{ #context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Test','1')},Struts2在解析时就会执行这段OGNL表达式,把响应头改了。这还只是验证漏洞存在。真正危险的是%{ (#_memberAccess['allowStaticMethodAccess']=true)(@java.lang.Runtime@getRuntime().exec('whoami'))}这种,直接执行系统命令。
我见过最离谱的案例是一个电商网站。他们的搜索框参数名是search,攻击者改成search%{ ...},Struts2照样解析。当时用的版本是2.3.15,官方在2.3.15.1里修了,但很多公司没及时升级。那个电商网站被植入了挖矿脚本,CPU跑满了一周才发现。
为什么这个漏洞影响这么大?Struts2在政府、金融、电信行业用得极多。很多老系统从2008年就没动过,Java版本还是6,Struts2还是2.0。这些系统往往直接暴露在公网,WAF规则又跟不上OGNL的变形。攻击者用#context、#_memberAccess这些绕过手法,简单混淆就能过掉大部分防护。
修复方案其实不复杂。升级到2.5.22以上,或者2.3.35以上。如果升不了,就在web.xml里加个过滤器,过滤掉参数名里的%{ 、${ 、#这些字符。但很多运维不知道,或者不敢动老系统。我见过一个银行的内网系统,明明打了补丁,但测试环境没打,攻击者从测试环境跳板进了生产网。
还有个坑是Struts2的插件。比如REST插件、JSON插件,它们有自己的参数解析逻辑。2017年的S2-045漏洞就是通过Content-Type头注入的,跟参数名没关系。这说明Struts2的攻击面比想象中广。我当时写了个脚本,批量扫描Content-Type里的%{ ,扫了三千个IP,命中四十多个。
现在回头看,Struts2反序列化漏洞的本质是框架设计时把“方便”放在了“安全”前面。OGNL表达式能直接访问Java运行时,这本身就是个定时炸弹。后来Spring MVC也出过类似问题,但Spring的表达式语言默认限制更多。Struts2的教训是:任何把用户输入当代码执行的框架,迟早会出事。
如果你还在维护Struts2系统,别只看版本号。检查所有插件的配置,确认struts.enable.DynamicMethodInvocation是false,struts.devMode也是false。开发模式会暴露更多OGNL入口。我见过一个系统,生产环境开着devMode,攻击者直接通过?debug=command&expression=...执行命令。这种配置错误比漏洞本身更致命。
