Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2022-22965 — CVE-2022-22965(Spring4Shell)的深入技术分析,包含环境设置、调试演练和漏洞利用链分解,用于教育性实验练习。 | Kitploit
工具/GitHubGitHub/khidottrivi/cve-2022-22965
漏洞分析代码分析漏洞利用Web应用程序漏洞利用学习与教育实验室与实践
GitHubkhidottrivi/cve-2022-22965

CVE-2022-22965

CVE-2022-22965(Spring4Shell)的深入技术分析,包含环境设置、调试演练和漏洞利用链分解,用于教育性实验练习。

查看仓库
4114年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE 2022-22965_Spring4Shell 分析

漏洞描述

Spring4Shell 是存在于 Spring Framework 的 Spring Core 上的一个 CVE 的名称。

其 CVSS 3.x 评分为 9.8,该漏洞被列为最高风险等级(critical)。该漏洞允许攻击者远程执行利用代码并控制存在漏洞的服务器。

鉴于 Spring Core 在互联网上的普及程度以及 Spring4Shell 的严重影响,专家们评估该漏洞的影响力不亚于 Log4shell。

影响范围

Spring4Shell 并不会影响互联网上所有使用 Spring Framework 的 Web 应用,它要求 Web 应用必须满足以下条件:

  • 应用使用的 Spring Framework 版本 < 5.2、5.2.0 – 5.2.19 或 5.3.0 - 5.3.17
  • 应用使用了 Spring-webmvc 或 Spring-webflux 两个依赖之一
  • 应用使用 jdk 版本 >= 9 的 java
  • 应用以传统 Java Web 归档格式(.war 文件)打包,并部署在 Tomcat 上(尚未发现使用 Springboot 运行的应用存在该漏洞)

环境搭建

我搭建的环境参数如下:

  • Spring Framework 5.1.0
  • Spring-webmvc dependency 5.1.0
  • JDK 11.0.13(我使用 Kali 2021.4a 虚拟机,这个 Java 版本是预装的)
  • Apache Tomcat 9.0.45

创建环境、包含漏洞的项目并使用 Intellij 设置调试

  1. 安装 Apache Tomcat

    如上所述,我使用 Kali 2021.4a 和 Apache Tomcat 9.0.45。如果你不知道如何安装 Apache Tomcat,并希望在 Kali Linux 上安装,可以参考这个链接。

    注意:将链接 https://mirror.kiu.ac.ug/apache/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz 替换为 https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz

  2. 选择 IDE

    我们需要一个 IDE 来编写项目代码、将项目打包为 .war 文件,以及一个非常重要的功能——调试。我使用 Intellij,你完全可以使用 Eclipse 或 Netbeans 等……只要是支持 Java 的 IDE 都可以。

  3. 创建一个包含漏洞的简单项目

    我的项目非常简单,包括:

    • 一个 model HelloWorld.java

      Untitled

    • 一个 controller HelloWorldController.java

      Untitled

    • 一个 view hello.jsp

      Untitled

  4. 构建 .war 文件

    要打包项目,请按以下步骤操作:Build -> Build Artifacts -> helloworld:war -> Build。

    等待 Build 进程成功完成,此时项目会多出一个 out 文件夹,进入 ./out/artifacts/your_war_name/ 你会看到一个 your_war_name.war 文件,这个 .war 文件就是编译打包后的 Web 项目,可用于部署到 Apache Tomcat 等 Java Servlet 上。

    如果 Build Artifacts 呈灰色(无法 Build Artifacts),那是因为尚未为该 Project 配置 Build Artifacts,你可以进入:File -> Project Structure -> Artifacts -> 删除所有现有 artifacts -> Add(+ 号)-> Web Application: Exploded -> From Modules... -> OK(完成 Exploded 的创建)> Add(+ 号)-> Web Application: Archive -> For 'helloworld:war exploded' -> OK。然后重新执行 Build Artifacts。

  5. 部署并设置调试

    • 部署

      要将 .war 文件部署到 Apache Tomcat,只需将 .war 文件复制到 Apache Tomcat 目录内的 /webapps 文件夹中(例如:我会将 helloworld.war 文件(为了方便调用我改了名)复制到 /opt/tomcat/apache-tomcat-9.0.45/webapps/ 目录)。然后,通过两种方式(适用于 Linux)启动 Tomcat 服务器:

      • /opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh start(应用将以执行此命令的用户权限运行,对我来说是 root@@)
      • sudo service tomcat start(应用通常以 tomcat 权限运行,取决于你在安装 Apache Tomcat 时如何配置服务)

      部署完成后,访问 http://localhost:8080/helloworld

    • 设置调试

      要设置(远程)调试 Tomcat,请按以下步骤操作:

      1. 服务器端:

        • 打开 catalina.sh 文件,将 JPDA_ADDRESS 参数的值从 localhost 改为虚拟机IP

          Untitled

        • 使用以下命令重新启动 Tomcat 服务器:/opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh jpda start。此时,除了为 HTTP Server 打开 8080 端口外,Tomcat 还会额外打开 8000 端口供我们连接并进行调试

        注意:在这个调试部分中,我是在 Windows 10 上运行 Intellij,在 Kali 虚拟机上运行 Tomcat,因此才需要修改 JDPA_ADDRESS;如果你在同一台机器上设置 Intellij 和 Windows 10,则无需修改。

      2. Intellij 端:

        • 进入 Run -> Edit Configurations... -> Add(+ 号)-> Remote JVM Debug

        • 命名 -> 将 Host 和 Port 修改为你之前在 catalina.sh 文件中修改的 IP 和端口 -> OK -> Shift + F9(启动调试)

          Untitled

详细分析

首先,我来分析一下我用于调试的项目,如上所述,这个项目很简单,只包含:

  • 一个 model HelloWorld.java,其中 HelloWorld 对象有两个属性:message(string)、person(string),以及 setter、getter 函数(因为结构如此简单,所以这个对象被称为 Plain Old Java Object - POJO)。项目中必须存在一个 POJO class——这是利用 Spring4Shell 漏洞的必要条件。
  • 一个 controller HelloWorldController.java,该类中有一个 helloPost 函数,其输入参数包括对象 helloWorld(HelloWorld)和 model(Model)。在 helloPost 函数中,会根据 helloWorld(person 和 message)属性的值为 model 对象执行 addAttribute——利用 Spring4Shell 漏洞的第二个条件是必须有一个 controller 接收 POJO 对象作为输入。
  • 一个 view hello.jsp,该 hello.jsp 文件会调用 model 中的各种 attribute(从 controller HelloWorldController.java 发送过来)并显示给用户。

我有一个示例如下:

Untitled

应用从 Post 请求的 params 中获取信息,并创建了一个对象 helloWorld{“person”:“Leo”, “message”:“Hi there”},这个 helloWorld 对象正是 helloPost 函数的输入。应用会执行我上面提到的操作,以向用户返回那个 response。

从 Post 请求 body 中的 parameters 转换为 helloWorld 对象的过程完全由 Spring 自动完成,那么它是如何做到的呢?它是否会验证输入的 parameters 呢?

源头(Source)class CachedIntrospectionResults

这张图片是在 Debug 过程中截取的,示例使用 body 为 “class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT” 发起请求(我将左侧(stack trace)称为 (1),右侧称为 (2)):

Untitled

在 (1) 中我高亮了需要注意的点(从下往上看),Spring 会根据 Post 请求的 params 对 helloWorld 对象执行 applyPropertyValue。如果 params 只是简单的 person=Leo&message=Hi%20there,Spring 就能找到关键字 'person' 对应 helloWorld.person,'message' 对应 helloWorld.message。

但 Spring 还允许我们通过 HTTP 请求发送对象(说通过 HTTP 发送对象有点夸张,但可以粗略这么理解)。我假设我的 person 属性不再是 string,而是一个 Person 对象,Person 中包含两个子属性:name(string)和 age(int)。要向服务器发送这个 Person 对象的信息,格式如下:“person.name=Leo&person.age=23”。

因此 params 的形式将是 A.B.C.D… = X,而不再只是 A=X。为了处理 A.B.C.D… = X 这种形式,假设有一个像 A.B.C= X 这样的 param,简单来说 Spring 会做这样的工作:将上述片段转换为 getA.getB.setC(X)。

我不解释 getA 是什么,而是以 body request 为 “person.name=Leo&person.age=23” 的情况为例:Spring 会在 helloWorld 对象中查找是否有 person 属性和 getPerson 函数,如果有,Spring 会调用 helloWorld.getPerson(),此时 Spring 会得到一个类型为 Person 的对象,我暂且称之为 person1,然后 Spring 会在 person1 中查找是否有名为 'name' 的属性以及 setName 函数(因为 'name' 后面是 '=' 号),如果有,Spring 就会为 person1 调用 setName(Leo)。

对于 person.age,Spring 不会重新从头查找 person 再到 age,而是会复用之前已有的对象,在这种情况下是 helloWorld 和 person1。

经过上述步骤后,此时服务器上会有一个对象 helloWorld{person:{name:”Leo”, age:23}}(暂时忽略 message 属性)。

那么 Spring 是如何找到每个对象的属性的呢?例如 helloWorld 对象的 'person' 属性?

你可以看到 (1) 的开头有一个 CachedIntrospectionResults(beanClass) 函数,该函数会列出 beanClass 的所有属性。看 (2) 你会发现,当 beanClass 是 model.HelloWorld 时,会有 3 个属性。而我创建的 HelloWorld model 只有 'person' 和 'message' 两个属性,因此上述函数多返回了一个 'class' 属性,如果你展开 'class' 这一行,会看到 propertytype 是 'java.lang.class'

因此我们可以影响一个 type 为 java.lang.classclass 的 class 对象 -> 这正是 Spring4Shell 的根源(source)。

CVE-2010-1622

关于上述 source,此前已存在一个与之相关的 CVE-2010-1622。CVE-2010-1622 的作者使用 payload class.classLoader.URLs[0] = X. 利用了该 source。

因为在 java.lang.class 类中包含 getClassLoader() 函数,它返回一个 ClassLoader 对象,而这个 ClassLoader 可以影响到 Tomcat 的 URLs 数组(用于加载资源)。由于能够影响 URLs,攻击者可以将 URLs[0] 的值改为一个 URL 地址,从而远程访问一个恶意 Jar 文件(由攻击者控制)。

为了修复这个漏洞,Spring 在 CachedIntrospectionResults(beanClass) 函数中进行了过滤(黑名单):

Untitled

下载工具