0x01 漏洞介绍
Spring Framework 是一个开源的轻量级J2EE应用程序开发框架。
3月31日,VMware发布安全公告,修复了Spring Framework中的远程代码执行漏洞(CVE-2022-22965)。在 JDK 9 及以上版本环境下,可以利用此漏洞在未授权的情况下在目标系统上写入恶意程序从而远程执行任意代码。
0x02 影响范围
影响组件:org.springframework:spring-beans
影响版本:< 5.3.18 和 < 5.2.20.RELEASE 的Spring框架均存在该漏洞
JDK版本:JDK>=9
部署方式:war包部署在TOMCAT中
0x03 漏洞原理
漏洞爆发之后,在学习大佬的分析之后发现,这个Spring最新0day漏洞其实不是全新的那种新洞,而是CVE-2010-1622这个漏洞的一种绕过情况。
这个CVE-2010-1622漏洞的原因是Spring参数绑定时,可以注入一个Java pojo对象,这个对象可以是恶意的去注册一些敏感tomcat的属性,最后通过修改Tomcat的配置来执行危险操作。
所以最新的CVE-2022-22965漏洞就是绕过了这个限制,可以说是Java 9的环境下坑了Spring一把,JDK9中存在可以绕过黑名单禁用的类,导致了这个漏洞,最后利用方式也就和之前一样了。
下面部分细讲这个问题。
0x04 Spring参数绑定
首先就是先理一下Spring中的参数绑定
简单来说,springmvc中可以自动的去给参数赋值。
例如我们常见的穿参数的方式就是下面这种
http://localhost:8080/spring4shell_war/?name=zzz&age=123
参数绑定的实现方式
@ControllerpublicclassHelloController{@GetMapping("/")publicStringindex(Person person){Person person1 =newPerson();
person1.setName(person.getName());
person1.setAge(person.getAge());return"hello";}}
这种方式就是直接传参数是一个Person对象,而不是以前的
@RequestParam
这种获取方式
publicStringHelloController(@RequestParam(required=false)String name,@RequestParam("age")int age){
这种参数绑定的实现方式方法就是如果用户传入name=zzz,则Spring框架会自动调用person.setName(‘zzz’)进行赋值。 如果提交的参数中出现了Person类的一个public字段或方法,就自动用户提交请求给他赋值。
0x05 调试过程
1)用户请求经过tomcat处理后,调用Spring总入口DispatcherServlet.java的doDispath方法来路由处理http请求:
org.springframework.web.servlet.DispatcherServlet#doDispatch
方法具体实现数据绑定
org.springframework.beans.AbstractPropertyAccessor#setPropertyValues(org.springframework.beans.PropertyValues, boolean, boolean)
nestedPa = getPropertyAccessorForPropertyPath(propertyName);那么看一下里面是什么
调用递归函数getPropertyAccessorForPropertyPath获取参数值,循环查看参数中是否包含"[" “]‘’ ‘’.”
若存在则按分割赋值给nestedProperty,我这个是没有的所以返回-1了。
然后换一个payload会怎么样class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
这个时候pos就是5了,取出来第一个。后面class
BeanWrapperImpl#getCachedIntrospectionResults().getPropertyDescriptor(propertyName)
这里就是最开始我看到文章中分析的,会在缓存cache里去找我们输入的参数propertyName
最终在org.springframework.beans.CachedIntrospectionResults#getPropertyDescriptor
这里就可以看到都可以获取到什么了。
补丁的绕过的问题
红色是原来的补丁,绿色是现在的修复
所以原来是黑名单的判断逻辑,beanClass非Class或者属性name非(classLoader|protectionDomain),
JDK8中没有只能用去class.classLoader调用
但是最新的CVE-2022-22965 用的class.module.classLoader,这样就就是绕过了这个限制。
原因是在Java 9以后,Class对象中多了一个Module类的属性,而Module类中也存在getClassLoader()方法,可以获取到一个class.module.classLoader
这次修补的理解就是:如果其中的属性是
ClassLoader
和
ProtectionDomain
,就直接continue跳过。
利用
这个漏洞的本质利用Java 9中的模块里一些内部对象的属性注入
我们现在已知道的PAYLOAD就是更改Tomcat将一些全局配置
就是修改保存在classLoader.resources.context这个context中日志的格式与文件名
就是下面的这些
class.module.classLoader.resources.context.parent.pipeline.first.pattern=xxx& 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=tomcatwar& class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
最后写在webapps/ROOT这个目录的一个webshell
0x06 坑点
还有就是在调试的时候,如果是在idea里面调试部署tomcat,最终测试会找不到webshell。
这是因为idea是映射,并不在这个目录,所以你访问原版的tomcat里面并没有,其实是在idea的一个目录下。
还有就是每次写完shell会有缓存,如果发现没重复打payload没写成,就重启一下tomcat服务就好了。
0x06 参考链接
https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement
SpringMVC框架任意代码执行漏洞(CVE-2010-1622)分析 - Ruilin (rui0.cn)
版权归原作者 god_Zeo 所有, 如有侵权,请联系我们删除。