Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索
字数 1694 2025-08-10 08:29:04
Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索
0x00: 背景
Spring Boot 项目通常打包成 FatJar(包含所有依赖的 jar),运行时 classpath 包括:
- BOOT-INF/classes 目录
- BOOT-INF/lib 目录下的所有 jar
这使得在运行时无法直接往 classpath 中增加文件。传统 webshell 方法难以奏效,因此需要探索新的 RCE 方法。
0x01: 类装载与类初始化
关键区别
类装载(Class loading):
- 由 ClassLoader 完成
- 被动触发(引用类时)或主动触发(loadClass/forName)
- 完成字节码读取和 Class 类型定义
- 不执行任何类代码
类初始化(Class initialization):
- 发生在类装载之后
- 触发时机:访问静态属性/方法、new、newInstance、Class.forName等
- 会执行 static 代码块和构造器代码
代码示例
// 仅类装载
classLoader.loadClass(className);
Class.forName(className, false, classLoader);
// 类初始化
classLoader.loadClass(className).newInstance();
Class.forName(className, true, classLoader);
0x02: 漏洞利用思路
通过写文件漏洞控制类初始化过程,实现代码执行:
- 找到可控的类初始化触发点
- 通过写文件覆盖关键系统类
- 触发初始化执行恶意代码
0x03: 文件写入目标
目标选择
由于无法直接写入应用 classpath,选择写入 JDK HOME 目录下的系统 jar 文件:
- JVM 采用"懒加载"机制,不会一开始加载所有系统 jar
- 需要选择启动后未被"Opened"的系统 jar
理想目标
/jre/lib/charsets.jar 是理想目标,因为:
- 默认不加载(除非使用
Charset.forName) - 包含字符集相关类
- 可被多种场景触发
常见 JDK 目录
/usr/lib/jvm/java-8-oracle/jre/lib/
/usr/lib/jvm/java-1.8-openjdk/jre/lib/
/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/
0x04: 可控类初始化场景
场景零:Spring 原生场景
触发路径:
- 请求头
Accept被HeaderContentNegotiationStrategy处理 - 调用
MediaType.parseMediaTypes() - 最终调用
Charset.forName(value)
利用方式:
GET / HTTP/1.1
Accept: text/html;charset=GBK
场景一:Fastjson 最新版(1.2.76)默认配置
利用条件:
- Fastjson 默认配置
java.nio.charset.Charset在白名单中
触发路径:
- 解析 JSON 时找到
Charset类 - 调用
Charset.forName(strVal) - 加载自定义字符集类
利用 payload:
{
"x":{
"@type":"java.nio.charset.Charset",
"val":"GBK"
}
}
场景二:Jackson 开启 enableDefaultTyping
(详细实现参考原文或测试代码)
场景三:JDBC URL getConnection
(详细实现参考原文或测试代码)
场景四:直接 Class.forName
(详细实现参考原文或测试代码)
场景五:直接 loadClass newInstance
(详细实现参考原文或测试代码)
0x05: 测试环境搭建
测试代码和 Docker 环境已托管在 GitHub:
https://github.com/landgrey/spring-boot-upload-file-lead-to-rce-tricks
包含:
- 漏洞测试环境
- 各种利用场景的示例代码
- 详细实现细节
防御建议
- 严格控制文件写入权限
- 监控 JDK 目录的文件变更
- 及时更新 Fastjson/Jackson 等组件
- 禁用不必要的 JSON 类型推导功能
- 使用安全的字符集处理方法
参考文章
- when-class-loading-initialization
- Improving Performance with Caching
- Understanding Extension Class Loading
- 深入探讨 Java 类加载器
- 深入理解Java类加载
- 细说Class.forName()底层实现
- LeadroyaL/fastjson-blacklist
原文首发: https://landgrey.me/blog/22/