CVE-2025-48734 与 CVE-2022-22965 漏洞分析:从Spring到Commons BeanUtils的RCE利用
字数 4959 2025-11-05 23:45:18

CVE-2022-22965 与 CVE-2025-48734 漏洞深度分析与教学

文档版本: 1.0
发布日期: 2025-10-09

1. 前言与概述

CVE-2022-22965(俗称Spring4Shell或SpringShell)和CVE-2025-48734是两个在利用原理上高度相似的远程代码执行漏洞。它们的核心都在于利用Java框架中属性绑定功能的缺陷,通过精心构造的嵌套属性路径,最终操纵Tomcat的AccessLogValve组件,实现Webshell的写入与任意命令执行。

本教学文档将深入分析这两个漏洞的技术细节,从环境搭建、漏洞复现到原理剖析和修复方案,提供一个全面的学习路径。


2. CVE-2022-22965 (Spring4Shell) 漏洞分析

2.1 漏洞描述与影响版本

该漏洞存在于Spring框架处理数据绑定的机制中。攻击者可以通过HTTP请求传递特定的嵌套参数,绕过限制,直接访问并修改Java对象的关键属性,最终导致RCE。

  • 受影响版本:
    • Spring框架版本 < 5.3.18 或 < 5.2.20
    • 使用SpringBoot等衍生框架的对应版本。
    • Tomcat版本 < 9.0.62(作为利用链的一部分,非漏洞根源)。
2.2 环境搭建
  1. 项目创建: 创建一个Spring Boot项目,JDK版本需大于1.9。
  2. 依赖配置:pom.xml中明确指定易受攻击的版本。
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version> <!-- 此版本内含Spring 5.3.15 -->
    </parent>
    <dependencies>
        <!-- 其他依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId> <!-- 打包为WAR并部署到独立Tomcat -->
        </dependency>
    </dependencies>
    
  3. 创建Controller: 编写一个简单的Controller,接收一个对象作为参数,例如User对象。
  4. 部署: 将项目打包成WAR文件,部署到Tomcat 9.0.62以下版本的服务器上。
2.3 漏洞复现
  1. 获取POC: 使用公开的POC脚本,例如来自GitHub的Spring4Shell-POC
  2. 执行攻击: 运行POC脚本,目标指向你的测试环境。POC会发送一个特殊的POST请求,其中包含恶意的参数。
  3. 验证利用: 攻击成功后,POC会在Tomcat的webapps目录下写入一个JSP Webshell。通过访问http://localhost:8088/tomcatwar.jsp?pwd=j&cmd=calc即可执行命令(如打开计算器)。
2.4 漏洞原理深度剖析

关键点:Spring MVC的数据绑定机制。

当Spring MVC接收到请求参数(如user.name=abc)时,它会尝试将参数值绑定到处理程序方法的参数对象(如User对象)的对应属性上。这个过程由WebDataBinder及其核心方法doBind()完成。

漏洞触发流程:

  1. 参数解析: POC发送的参数类似class.module.classLoader.resources.context.parent.pipeline.first.pattern=...WebDataBinder会调用getPropertyAccessorForPropertyPath方法递归解析这个以点分隔的嵌套属性路径。
  2. 递归获取属性(Getter链): 该方法会从左至右,逐级调用属性的Getter方法,并将返回的对象包装为BeanWrapperImpl实例,作为下一级属性解析的起点。
    • user.getClass() -> 返回java.lang.Class对象。
    • class.getModule() -> 返回java.lang.Module对象。
    • module.getClassLoader() -> 返回Tomcat的WebappClassLoader对象。
    • classLoader.getResources() -> 返回Tomcat的StandardRoot对象。
    • resources.getContext() -> 返回当前Web应用的StandardContext对象。
    • ... 最终到达 pipeline.getFirst() -> 返回AccessLogValve对象。
  3. 属性赋值(Setter): 当解析到最后一个属性(如pattern)时,流程会进入setValue方法,通过反射调用AccessLogValve对象的setPattern方法,将POC中提供的恶意值写入。

为什么能写入Webshell?

  • Tomcat的AccessLogValve: 这是Tomcat用于记录访问日志的组件。通过设置其属性,可以控制日志文件的存放位置、名称和内容。
  • 恶意Pattern: POC中设置的pattern值通常包含类似%{crypto}i的占位符,并会同时设置一个请求头(如crypto: <% ... %>),这使得最终写入的日志文件内容是一段JSP Webshell代码。
  • 文件路径控制: 同时设置directory(目录)、prefix(前缀)、suffix(后缀,如.jsp)等属性,将Webshell写入web应用目录下,从而可直接访问。
2.5 漏洞修复

Spring 5.3.18/5.2.20版本的补丁核心修改在于限制了可绑定的属性范围

  • 补丁逻辑:BeanWrapperImpl中,当遍历一个类的属性以缓存其Getter/Setter方法时,如果发现目标的Bean类是java.lang.Class,则只允许绑定其name属性或类似XXXName的Getter方法。明确禁止了通过class属性访问ClassLoader的路径,从根本上切断了利用链。

3. CVE-2025-48734 (Commons BeanUtils RCE) 漏洞分析

3.1 漏洞描述与影响版本

该漏洞是Apache Commons BeanUtils库中的访问控制不当漏洞。其原理与Spring4Shell惊人地相似,但触发点不同。它利用了BeanUtils默认允许访问枚举(Enum)对象的declaringClass属性,从而同样可以访问到ClassLoader

  • 受影响版本: Apache Commons BeanUtils <= 1.10.1
3.2 环境搭建
  1. 项目创建: 创建一个简单的Web项目(如Servlet项目),并引入易受攻击版本的Commons BeanUtils依赖(<= 1.10.1)。
  2. 关键代码: 在代码中需要存在使用BeanUtils.populate(Object bean, Map properties)方法的场景,并且被填充的bean对象是一个枚举(Enum)类型。这是该漏洞利用的一个关键前提,在实际应用中相对少见。
3.3 漏洞复现
  1. 构造请求: 发送HTTP请求,请求参数为恶意的嵌套属性路径,例如:declaringClass.resources.context.parent.pipeline.first.pattern=...(与Spring4Shell后续路径基本一致)。
  2. 执行攻击: 应用使用BeanUtils.populate(enumObj, request.getParameterMap())处理请求,触发漏洞。
  3. 验证利用: 与Spring4Shell类似,成功后在Tomcat目录下写入Webshell,并可执行命令。
3.4 漏洞原理深度剖析

关键点:Commons BeanUtils的属性访问机制。

  1. 入口点: BeanUtils.populate()方法会遍历请求参数Map,对每个键值对调用setProperty方法。
  2. 属性解析:setProperty内部,会调用getPropertyUtils().getProperty()来解析嵌套属性路径。其内部使用BeanPropertyAccessor进行递归解析,逻辑与Spring的BeanWrapperImpl类似。
  3. 利用链触发:
    • resolver.next(name)首先解析出declaringClass
    • target是枚举对象,调用enumObj.getDeclaringClass()方法,返回该枚举常量所属的枚举类(一个Class对象)。
    • 此时,攻击者已经获得了对一个Class对象的控制权。后续的路径resources.context.parent...与Spring4Shell完全一致,可以继续访问到Tomcat的AccessLogValve并修改其属性。
  4. 赋值: 解析到最后一级属性(如pattern)后,调用getPropertyUtils().setProperty(target, name, newValue)完成赋值,实现Webshell写入。
3.5 漏洞修复

在Commons BeanUtils 1.11.0及更高版本中,修复方案是引入了黑名单机制

  • 补丁逻辑:PropertyUtilsBeanresetBeanIntrospectors方法中,添加了一个默认启用的FilteredBeanIntrospector。该过滤器将declaringClass属性列入黑名单,禁止通过BeanUtils访问枚举类的此属性,从而切断了利用链的起点。

4. 漏洞对比与总结

特征 CVE-2022-22965 (Spring4Shell) CVE-2025-48734 (Commons BeanUtils)
漏洞根源 Spring Framework 数据绑定机制 Apache Commons BeanUtils 属性访问机制
利用起点 任意POJO的class属性 枚举(Enum)对象的declaringClass属性
核心技术 通过嵌套属性路径递归调用Getter/Setter 通过嵌套属性路径递归调用Getter/Setter
最终利用 控制Tomcat AccessLogValve属性,写入Webshell 控制Tomcat AccessLogValve属性,写入Webshell
修复方式 白名单限制(仅允许Class绑定特定属性) 黑名单限制(禁止访问declaringClass属性)
利用前提 相对宽泛,只需参数绑定功能 较苛刻,需populate一个枚举对象

核心共性:
这两个漏洞都揭示了Java生态中一个常见的安全风险:过于强大的数据绑定功能。当框架允许将用户输入直接、无限制地映射到对象属性时,如果攻击者能够构造出一条从起始对象到危险对象(如ClassLoader)的属性路径,就可能造成严重的后果。

5. 安全建议

  1. 及时升级: 尽快将Spring框架升级至5.3.18+ / 5.2.20+,将Commons BeanUtils升级至1.11.0+。
  2. 最小化数据绑定: 在开发中,避免使用自动绑定所有参数的模式。应使用DTO(数据传输对象)或明确指定允许绑定的字段(白名单)。
  3. 深度防御: 即使升级了框架,也建议部署WAF等安全设备,对包含classclassLoaderdeclaringClass等关键词的请求进行检测和拦截。
  4. 代码审计: 检查项目中是否存在使用BeanUtils.populate且参数为外部可控(如HTTP请求参数)的情况,特别是当参数对象类型为枚举时,需高度警惕。

参考资料:

CVE-2022-22965 与 CVE-2025-48734 漏洞深度分析与教学 文档版本: 1.0 发布日期: 2025-10-09 1. 前言与概述 CVE-2022-22965(俗称Spring4Shell或SpringShell)和CVE-2025-48734是两个在利用原理上高度相似的远程代码执行漏洞。它们的核心都在于利用Java框架中 属性绑定 功能的缺陷,通过精心构造的嵌套属性路径,最终操纵Tomcat的 AccessLogValve 组件,实现Webshell的写入与任意命令执行。 本教学文档将深入分析这两个漏洞的技术细节,从环境搭建、漏洞复现到原理剖析和修复方案,提供一个全面的学习路径。 2. CVE-2022-22965 (Spring4Shell) 漏洞分析 2.1 漏洞描述与影响版本 该漏洞存在于Spring框架处理数据绑定的机制中。攻击者可以通过HTTP请求传递特定的嵌套参数,绕过限制,直接访问并修改Java对象的关键属性,最终导致RCE。 受影响版本: Spring框架版本 < 5.3.18 或 < 5.2.20 使用SpringBoot等衍生框架的对应版本。 Tomcat版本 < 9.0.62(作为利用链的一部分,非漏洞根源)。 2.2 环境搭建 项目创建: 创建一个Spring Boot项目,JDK版本需大于1.9。 依赖配置: 在 pom.xml 中明确指定易受攻击的版本。 创建Controller: 编写一个简单的Controller,接收一个对象作为参数,例如 User 对象。 部署: 将项目打包成WAR文件,部署到Tomcat 9.0.62以下版本的服务器上。 2.3 漏洞复现 获取POC: 使用公开的POC脚本,例如来自GitHub的 Spring4Shell-POC 。 执行攻击: 运行POC脚本,目标指向你的测试环境。POC会发送一个特殊的POST请求,其中包含恶意的参数。 验证利用: 攻击成功后,POC会在Tomcat的webapps目录下写入一个JSP Webshell。通过访问 http://localhost:8088/tomcatwar.jsp?pwd=j&cmd=calc 即可执行命令(如打开计算器)。 2.4 漏洞原理深度剖析 关键点:Spring MVC的数据绑定机制。 当Spring MVC接收到请求参数(如 user.name=abc )时,它会尝试将参数值绑定到处理程序方法的参数对象(如 User 对象)的对应属性上。这个过程由 WebDataBinder 及其核心方法 doBind() 完成。 漏洞触发流程: 参数解析: POC发送的参数类似 class.module.classLoader.resources.context.parent.pipeline.first.pattern=... 。 WebDataBinder 会调用 getPropertyAccessorForPropertyPath 方法递归解析这个以点分隔的嵌套属性路径。 递归获取属性(Getter链): 该方法会从左至右,逐级调用属性的Getter方法,并将返回的对象包装为 BeanWrapperImpl 实例,作为下一级属性解析的起点。 user.getClass() -> 返回 java.lang.Class 对象。 class.getModule() -> 返回 java.lang.Module 对象。 module.getClassLoader() -> 返回Tomcat的 WebappClassLoader 对象。 classLoader.getResources() -> 返回Tomcat的 StandardRoot 对象。 resources.getContext() -> 返回当前Web应用的 StandardContext 对象。 ... 最终到达 pipeline.getFirst() -> 返回 AccessLogValve 对象。 属性赋值(Setter): 当解析到最后一个属性(如 pattern )时,流程会进入 setValue 方法,通过反射调用 AccessLogValve 对象的 setPattern 方法,将POC中提供的恶意值写入。 为什么能写入Webshell? Tomcat的AccessLogValve: 这是Tomcat用于记录访问日志的组件。通过设置其属性,可以控制日志文件的存放位置、名称和内容。 恶意Pattern: POC中设置的 pattern 值通常包含类似 %{crypto}i 的占位符,并会同时设置一个请求头(如 crypto: <% ... %> ),这使得最终写入的日志文件内容是一段JSP Webshell代码。 文件路径控制: 同时设置 directory (目录)、 prefix (前缀)、 suffix (后缀,如 .jsp )等属性,将Webshell写入web应用目录下,从而可直接访问。 2.5 漏洞修复 Spring 5.3.18/5.2.20版本的补丁核心修改在于 限制了可绑定的属性范围 。 补丁逻辑: 在 BeanWrapperImpl 中,当遍历一个类的属性以缓存其Getter/Setter方法时,如果发现目标的Bean类是 java.lang.Class ,则只允许绑定其 name 属性或类似 XXXName 的Getter方法。 明确禁止了通过 class 属性访问 ClassLoader 的路径 ,从根本上切断了利用链。 3. CVE-2025-48734 (Commons BeanUtils RCE) 漏洞分析 3.1 漏洞描述与影响版本 该漏洞是Apache Commons BeanUtils库中的访问控制不当漏洞。其原理与Spring4Shell惊人地相似,但触发点不同。它利用了BeanUtils默认允许访问枚举(Enum)对象的 declaringClass 属性,从而同样可以访问到 ClassLoader 。 受影响版本: Apache Commons BeanUtils <= 1.10.1 3.2 环境搭建 项目创建: 创建一个简单的Web项目(如Servlet项目),并引入易受攻击版本的Commons BeanUtils依赖( <= 1.10.1)。 关键代码: 在代码中需要存在使用 BeanUtils.populate(Object bean, Map properties) 方法的场景,并且 被填充的 bean 对象是一个枚举(Enum)类型 。这是该漏洞利用的一个关键前提,在实际应用中相对少见。 3.3 漏洞复现 构造请求: 发送HTTP请求,请求参数为恶意的嵌套属性路径,例如: declaringClass.resources.context.parent.pipeline.first.pattern=... (与Spring4Shell后续路径基本一致)。 执行攻击: 应用使用 BeanUtils.populate(enumObj, request.getParameterMap()) 处理请求,触发漏洞。 验证利用: 与Spring4Shell类似,成功后在Tomcat目录下写入Webshell,并可执行命令。 3.4 漏洞原理深度剖析 关键点:Commons BeanUtils的属性访问机制。 入口点: BeanUtils.populate() 方法会遍历请求参数Map,对每个键值对调用 setProperty 方法。 属性解析: 在 setProperty 内部,会调用 getPropertyUtils().getProperty() 来解析嵌套属性路径。其内部使用 BeanPropertyAccessor 进行递归解析,逻辑与Spring的 BeanWrapperImpl 类似。 利用链触发: resolver.next(name) 首先解析出 declaringClass 。 target 是枚举对象,调用 enumObj.getDeclaringClass() 方法,返回该枚举常量所属的枚举类(一个 Class 对象)。 此时, 攻击者已经获得了对一个 Class 对象的控制权 。后续的路径 resources.context.parent... 与Spring4Shell完全一致,可以继续访问到Tomcat的 AccessLogValve 并修改其属性。 赋值: 解析到最后一级属性(如 pattern )后,调用 getPropertyUtils().setProperty(target, name, newValue) 完成赋值,实现Webshell写入。 3.5 漏洞修复 在Commons BeanUtils 1.11.0及更高版本中,修复方案是引入了 黑名单机制 。 补丁逻辑: 在 PropertyUtilsBean 的 resetBeanIntrospectors 方法中,添加了一个默认启用的 FilteredBeanIntrospector 。该过滤器将 declaringClass 属性列入黑名单, 禁止通过BeanUtils访问枚举类的此属性 ,从而切断了利用链的起点。 4. 漏洞对比与总结 | 特征 | CVE-2022-22965 (Spring4Shell) | CVE-2025-48734 (Commons BeanUtils) | | :--- | :--- | :--- | | 漏洞根源 | Spring Framework 数据绑定机制 | Apache Commons BeanUtils 属性访问机制 | | 利用起点 | 任意POJO的 class 属性 | 枚举(Enum)对象的 declaringClass 属性 | | 核心技术 | 通过嵌套属性路径递归调用Getter/Setter | 通过嵌套属性路径递归调用Getter/Setter | | 最终利用 | 控制Tomcat AccessLogValve 属性,写入Webshell | 控制Tomcat AccessLogValve 属性,写入Webshell | | 修复方式 | 白名单限制 (仅允许Class绑定特定属性) | 黑名单限制 (禁止访问 declaringClass 属性) | | 利用前提 | 相对宽泛,只需参数绑定功能 | 较苛刻,需 populate 一个枚举对象 | 核心共性: 这两个漏洞都揭示了Java生态中一个常见的安全风险: 过于强大的数据绑定功能 。当框架允许将用户输入直接、无限制地映射到对象属性时,如果攻击者能够构造出一条从起始对象到危险对象(如 ClassLoader )的属性路径,就可能造成严重的后果。 5. 安全建议 及时升级: 尽快将Spring框架升级至5.3.18+ / 5.2.20+,将Commons BeanUtils升级至1.11.0+。 最小化数据绑定: 在开发中,避免使用自动绑定所有参数的模式。应使用DTO(数据传输对象)或明确指定允许绑定的字段(白名单)。 深度防御: 即使升级了框架,也建议部署WAF等安全设备,对包含 class 、 classLoader 、 declaringClass 等关键词的请求进行检测和拦截。 代码审计: 检查项目中是否存在使用 BeanUtils.populate 且参数为外部可控(如HTTP请求参数)的情况,特别是当参数对象类型为枚举时,需高度警惕。 参考资料: 先知社区原文 https://mp.weixin.qq.com/s/Pz1iaKp1ZmrNS4iiTKyaZg https://www.anquanke.com/post/id/272149#h3-10