FastJson+SpringBoot:一条绕过 AutoType 的类加载 RCE 利用链深度复盘

· 2026-08-03 07:00 · 2 阅读

原创 KCyber 2026-08-03 07:00 北京

FastJson 反序列化的问题持续了很多年,从最早的随意指定 @type 类型触发 RCE ,到 1.2.25 引入 checkAutoType ,再到各种 bypass 姿势,比如我曾经公开过的 1.2.80 绕过:

https://mp.weixin.qq.com/s/gnZwj8A06cLbovcjHxHwHQ

以及不断被挖掘的第三方 gadget 。更高版本中的校验机制基本封死了 @type ,一度以为 FastJson 反序列化的故事已终结。然而新披露的漏洞证明:对 SpringBoot 等主流框架类加载机制的深度利用,配合 FastJson 的触发入口,仍可开辟新的攻击面。

特殊类加载导致有限 SSRF

在 checkAutoType 中,前面会进行黑名单校验以及 SafeMode 检查,往后走有一个判断逻辑:当根据 typeName 提取 class 为空时,会尝试将 typeName 转换获取 resource 并调用 getResourceAsStream 来处理 resource :

猜测可能存在 SSRF 的风险,不过从 typeName 中提取 resource 时,将 / 统一替换为了 . 。

普通的域名格式无法通过,可以用 ip 整数格式来绕过。但是最终发现没有触发 SSRF ,原因是 URLClassLoader 根本拿不到 URL :

那么有没有 URLClassLoader 的子类能够触发 URL 请求呢?漏洞原作者提到了 LaunchedURLClassLoader 类,这是一个 SpringBoot 执行 fatjar 启动时的核心加载类。换成对应环境启动分析,此时的 getResourceAsStream 会进入 findResource ,并触发对外 URL 请求:

因此,该 SSRF 仅在 SpringBoot fatjar 运行模式下成立,若无 LaunchedURLClassLoader 参与类加载,则无法触发。

jar 加载与缓存实现 RCE

getResourceAsStream 的目的是来加载 jar: ,支持 http 和 file 等获取方式,并将加载的 jar 放入 closeables 中:

修改 http 为 jar:http 伪协议,尝试提取指定的类对象,如果存在 JSONType 注解,会进行 loadClass 类加载:

但是类的名称有些特殊,无法正常加载:

在 Java 编译层虽然对类名有严格限制,但其实在 ASM 字节码层面来修改类名照样合法。修改后的类名可以满足需求,但是否可以加载成功呢?调试表明,当前生效的类加载器为 TomcatEmbeddedWebappClassLoader ,还是无法获取到类对象:

以前分析 Java XXE 漏洞时提到过 :

https://mp.weixin.qq.com/s/P-1vvvfiX33xLaGN3w4yTQ

jar:http 远程加载服务端 jar 文件,会在本地生成一个完整的 jar 缓存,比如 Windows 系统上如下:

若能预测临时文件路径,是否可通过构造第二个 @type + jar:file 请求完成类加载?注意这个临时文件很快就会删除 (可以通过 BlockingServer 长连接包保持缓存文件 ),并且文件以 .tmp 结尾,在 checkAutoType 中会被替换为 /tmp ,所以无法直接利用。但在 Linux 环境下, /proc/self/fd 下的文件描述符会保存该文件,此时第二个请求通过 jar:file 加载对应 fd 可以成功完成类加载:

jar:file:.proc.self.fd.xx!.xx //实际为 jar:file:/proc/self/fd/xx!/xx

最终实现了RCE 。那为什么jar:http行而jar:file 却可以呢?在 kzb 文章中讲到了原因: native 层在 Class.forName 时不允许出现连续的两个斜杠, 而file 刚好可以只用一个斜杠不受影响。

以上分析基于 SpringBoot 内置 Tomcat 环境。kzb 的文章中还指出,Undertow 通过 URLClassPath$Loader.getResource 加载远程 jar,不受双斜杠限制,可直接利用 jar:http 实现 RCE,此处不再赘述。

Fastjson2 中的延续

之后长亭又通报了 Fastjson2 的漏洞,可看成是上面 1.2.83 的延续。下面简单补充分析下。

与 Fastjson1 不同,FastJson2 的 checkAutoType 位于 ObjectReaderProvider 类,同样会进行 SafeMode 判断,当然最核心的区别是引入了 FNV-1a 哈希白名单校验机制。

当开启 autoTypeSupport 或者指定 objectClass 为 Object 类型时,checkAutoType 对 typeName 会做 hash 匹配,如果匹配成功后续 loadClass 类加载逻辑与前面分析的 1.2.83 类似。分析发现默认情况下, hash 白名单在 ObjectReaderProvider 构造函数中完成赋值,只有一个固定值为 -6293031534589903644L :

hashCodes[hashCodes.length - 1] = -6293031534589903644L;
Arrays.sort(hashCodes);
this.acceptHashCodes = hashCodes;

只需对该 hash 值进行碰撞,获取合法类名后即可复用前述利用链。具体利用过程不再展开。

修复方式

FastJson2 修复补丁中,在哈希值匹配命中后,新增了对原始类名文本的二次校验。系统会维护一份真实的白名单类名集合 acceptNameSet ,只有当哈希值匹配且实际字符串文本也与白名单中的类名完全一致时,才允许继续加载。同时修复版本会对非法的 URL 特殊字符进行了拦截:

漏洞本质上是对 SpringBoot 类加载机制的创新利用,FastJson 仅作为触发入口。

由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用本人负责,公众号及文章作者不为此承担任何责任。

跳转微信打开