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中明确指定易受攻击的版本。<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> - 创建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请求参数)的情况,特别是当参数对象类型为枚举时,需高度警惕。
参考资料: