spring框架远程代码执行漏洞
2022年3月29日深夜,框架Spring官方在GitHub上悄悄推了一个commit,远程修补了Spring Framework中的代码一个反序列化漏洞。当时没多少人注意到。执行第二天,漏洞漏洞细节被公开——CVE-2022-22965,框架后来被叫做“Spring4Shell”。远程攻击者可以通过构造特定的代码HTTP请求,在目标服务器上直接执行任意代码。执行不需要认证,漏洞不需要任何前置条件。框架一个curl请求就能拿到shell。远程
这个漏洞的代码本质是数据绑定机制被滥用。Spring MVC在处理请求参数时,执行会通过WebDataBinder把HTTP参数映射到Java对象的漏洞属性上。问题出在class.module.classLoader这条链上——攻击者能沿着这条属性路径,一路摸到Tomcat的AccessLogValve,然后动态修改日志配置,把日志文件后缀改成.jsp,日志目录指向web根目录,日志内容写入恶意代码。下一次请求触发日志写入,一个webshell就落在了服务器上。
整个利用链设计得极其精巧。它不是那种暴力反序列化ObjectInputStream的打法,而是把Spring的参数绑定、Java的反射机制、Tomcat的日志组件三个东西串在一起。单独看每个组件都没问题,连起来就是一条完整的RCE路径。这种“组合拳”式的漏洞,比单一组件的漏洞更难防——你很难在代码审计阶段就预判到这种跨组件的攻击面。
受影响的条件其实挺苛刻的。需要JDK 9及以上,需要Spring MVC或Spring WebFlux,需要部署在Tomcat上且以WAR包方式运行。Spring Boot内置Tomcat的fat jar部署方式不受影响。但偏偏国内大量传统项目就是WAR包+Tomcat的架构,JDK版本也普遍升到了11甚至17。所以这个漏洞在国内的实际影响面,比国外安全圈最初估计的要大得多。
修复方式有好几种。最直接的是升级到Spring Framework 5.3.18或5.2.20。如果暂时升不了,可以配一个@ControllerAdvice全局拦截器,把请求参数里带class.前缀的字段全部过滤掉。还有一种办法是给WebDataBinder设置disallowedFields,禁止绑定classLoader和protectionDomain。Tomcat那边也可以做缓解——在context.xml里把AccessLogValve的pattern属性写死,不给外部修改的机会。
我印象比较深的是漏洞公开后那几天,GitHub上冒出了一堆PoC仓库,有些写得相当完整,连批量扫描的脚本都配好了。国内几个安全群里的讨论从“这漏洞真的能打吗”到“我已经拿到好几台机器的shell了”,中间也就隔了不到48小时。这种速度说明一件事:从漏洞公开到大规模利用的窗口期,正在变得越来越短。
Spring官方后来的处理也值得说一句。他们在5.3.18版本里直接禁止了classLoader相关属性的绑定,算是从根上堵住了这条路。但这类漏洞不会只有这一个。Spring的参数绑定机制天然就是攻击面——只要框架允许通过HTTP参数动态设置对象属性,就永远存在被绕过的可能。开发者能做的,是尽量不用@ModelAttribute去绑定复杂对象,对请求参数做白名单校验,别把框架的便利性当成理所当然的安全边界。
