# 反序列化弱點偵查 [TOC] ## 什麼是反序列化漏洞? 序列化(Serialization)是將記憶體中的物件(Object)轉換成可以儲存(例如存入檔案或資料庫)或傳輸(例如透過網路)的位元組流或字串格式的過程。反序列化(Deserialization)則是相反的過程,將位元組流或字串還原成記憶體中的物件。 反序列化漏洞發生在:當應用程式反序列化來自**不可信來源**(例如使用者輸入、HTTP請求、Cookie、檔案等)的資料時,攻擊者可以精心構造惡意的序列化資料。當這些資料被反序列化時,可能會導致應用程式執行非預期的程式碼、修改物件狀態、繞過驗證、拒絕服務(DoS)或更嚴重的遠端程式碼執行(RCE)。 ## 識別反序列化漏洞通常遵循以下思路: 1. **尋找反序列化函數/方法:** 在程式碼中搜索執行反序列化操作的關鍵字或函式庫呼叫。 2. **追蹤資料來源:** 確定傳遞給這些反序列化函數的資料來源。如果資料來源是使用者可控的(例如 HTTP 請求的 Body、參數、Header、Cookie、上傳的檔案等),就存在潛在風險。 3. **分析資料格式:** 觀察傳輸的資料格式。常見的序列化格式包括: * **語言特定的二進位格式**(例如 Java 的 `ObjectOutputStream`, Python 的 `pickle`, Ruby 的 `Marshal`) * **JSON**(尤其是在啟用 Type Handling 時,如 .NET 的 Newtonsoft.Json 或 JavaScript 的某些函式庫) * **XML**(例如 .NET 的 `DataContractSerializer`, `XmlSerializer`, Java 的 XStream) * **PHP 特定格式** * **YAML** 4. **檢查是否有已知的 Gadget Chains:** 很多反序列化攻擊依賴於應用程式類別路徑(Classpath/Include Path)中存在的特定類別組合(稱為 "Gadget Chain")。這些類別的方法(例如 `__wakeup`, `__destruct`, `readObject`, `finalize` 等)會在反序列化過程中或之後被自動呼叫,攻擊者可以串聯這些呼叫來達到執行任意程式碼的目的。 5. **動態測試/模糊測試:** 使用工具(如 Burp Suite 的擴充功能、ysoserial、PHPGGC 等)或手動修改請求,發送已知或潛在的惡意序列化資料,觀察應用程式的反應(錯誤訊息、延遲、非預期行為)。 ## 特定語言的反序列化漏洞識別 ### Java * **危險函數/類別:** * `java.io.ObjectInputStream.readObject()`:最核心、最常見的反序列化入口。 * `java.beans.XMLDecoder.readObject()`:從 XML 反序列化物件。 * 第三方函式庫:如 XStream (`fromXML()`)、Jackson (`enableDefaultTyping()`)、Fastjson (`@type` 特性)、Kryo 等,如果配置不當或處理不可信資料也可能觸發。 * **資料格式特徵:** * Java 原生序列化:通常是二進位格式,Base64 編碼後常以 `rO0` (`aced` 的 Base64) 開頭。 * XMLDecoder:XML 格式。 * Jackson/Fastjson:JSON 格式,需注意是否啟用允許指定任意類型的功能(例如 Jackson 的 `enableDefaultTyping` 或 Fastjson 的 `@type`)。 * **識別方法:** * 程式碼審查:搜索 `readObject`, `XMLDecoder`, `XStream`, `ObjectMapper` (注意配置) 等關鍵字。 * 動態測試:尋找 Base64 編碼的資料,解碼後檢查是否以 `aced` (hex) 開頭。使用 `ysoserial` 工具生成針對目標環境中存在的 Gadget Chains (如 Commons Collections, Spring, Groovy, BeanShell 等) 的 Payload 進行測試。Burp Suite 有 Java Deserialization Scanner 等擴充功能可以輔助。 * **Gadget Chains:** 非常豐富,Commons Collections 系列最為著名,還有 Spring、Groovy、Hibernate、Rome 等多種函式庫的 Gadget。 ### PHP * **危險函數/類別:** * `unserialize()`:PHP 原生的反序列化函數,是主要入口。 * **資料格式特徵:** * PHP 序列化格式是人類可讀的文字格式,例如:`O:ClassName:NumProperties:{s:PropNameLength:"PropName";PropType:PropValue;...}` * 常見於 Cookie、POST 請求參數或資料庫中。 * **識別方法:** * 程式碼審查:搜索 `unserialize()` 函數,追蹤其參數來源是否可控。 * 動態測試:尋找 PHP 序列化格式的字串。使用 `PHPGGC` 工具生成針對目標環境中存在的 Gadget Chains (如 Monolog, Doctrine, Guzzle, SwiftMailer, Laravel/Symfony 框架相關等) 的 Payload 進行測試。 * **Gadget Chains:** 依賴於應用程式包含的函式庫和框架。攻擊通常利用魔術方法(Magic Methods)如 `__wakeup()`, `__destruct()`, `__toString()` 等在反序列化時自動觸發。這種利用方式稱為 Property Oriented Programming (POP)。 ### Python * **危險函數/類別:** * `pickle.load()`, `pickle.loads()`:Python 標準庫中最危險的反序列化模組,可以直接執行任意程式碼。 * `cPickle.load()`, `cPickle.loads()`:`pickle` 的 C 語言實現,同樣危險。 * `shelve`:基於 `pickle` 的持久化儲存模組。 * `PyYAML` 的 `yaml.load()`:在舊版本 (5.1 之前) 或未指定 `Loader=yaml.SafeLoader` 時,可以執行任意 Python 程式碼。 * 第三方函式庫:如 `jsonpickle`,如果處理不可信資料也可能存在風險。 * **資料格式特徵:** * `pickle`:二進位格式,可能包含 `.` (物件方法/屬性訪問)、`(` (標記)、`R` (執行命令) 等特殊字元。 * `PyYAML`:標準 YAML 格式,但可包含特殊的標籤 (Tag) 來指定 Python 物件或執行程式碼,如 `!!python/object/apply:os.system ['ls']`。 * **識別方法:** * 程式碼審查:搜索 `pickle.load`, `pickle.loads`, `yaml.load` (檢查 Loader 是否為 SafeLoader), `shelve`, `jsonpickle` 等。 * 動態測試:尋找看起來像 `pickle` 或 YAML 的資料。`pickle` 由於其執行程式碼的能力,構造 Payload 相對直接,通常利用 `__reduce__()` 方法。對於 `yaml.load`,嘗試注入 YAML 標籤來執行命令。 * **安全建議:** 強烈建議使用 `yaml.safe_load()` 替代 `yaml.load()`。絕對避免對不可信來源的資料使用 `pickle`。 ### .NET (C#, VB.NET) * **危險函數/類別:** * `System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize()`:非常危險,類似 Java 的 `ObjectInputStream`。 * `System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Deserialize()`:處理 SOAP 格式,同樣危險。 * `System.Runtime.Serialization.NetDataContractSerializer.ReadObject()`:XML 格式,也可能被利用。 * `System.Web.UI.ObjectStateFormatter.Deserialize()` (`LosFormatter`):用於 ASP.NET ViewState,若 ViewState 未加密或 MAC 校驗金鑰洩漏則可被利用。 * `System.Web.Script.Serialization.JavaScriptSerializer.Deserialize()` (配合 `SimpleTypeResolver`):JSON 格式,若允許解析任意類型則危險。 * `Newtonsoft.Json` (Json.NET) 的 `JsonConvert.DeserializeObject()`:當 `TypeNameHandling` 設置為 `All`, `Objects`, 或 `Auto` 時,允許在 JSON 中指定物件類型,導致反序列化漏洞。 * `System.Xaml.XamlServices.Load()` / `Parse()`:處理 XAML,也可被利用。 * **資料格式特徵:** * `BinaryFormatter`: 二進位。 * `SoapFormatter`, `NetDataContractSerializer`: XML。 * ViewState (`__VIEWSTATE`): Base64 編碼的字串,解碼後通常由 `LosFormatter` 或 `ObjectStateFormatter` 處理。 * Json.NET/JavaScriptSerializer: JSON,需注意 `$type` (Json.NET 預設) 或 `__type` (JavaScriptSerializer) 等類型指示符。 * **識別方法:** * 程式碼審查:搜索上述危險類別和方法。特別注意 `TypeNameHandling` 的配置。檢查 ViewState 的 MAC 驗證是否啟用和金鑰強度。 * 動態測試:尋找二進位、XML、ViewState 或包含 `$type` / `__type` 的 JSON 資料。使用 `ysoserial.net` 工具生成針對 .NET Gadget Chains (如 `ObjectDataProvider`) 的 Payload。Burp Suite 有 ViewState Editor 等擴充。 * **Gadget Chains:** 常用 `ObjectDataProvider` Gadget,還有 `WindowsIdentity` 等。 ### Node.js (JavaScript) * **原生風險較低:** JavaScript 原生的 `JSON.parse()` 通常被認為是安全的,它只解析資料結構,不會實例化任意類型的物件或執行程式碼(但超大 JSON 可能導致 DoS)。 * **危險函式庫/模式:** * `node-serialize`:一個第三方函式庫,其 `unserialize()` 方法存在已知的 RCE 漏洞(會執行 IIFE)。 * `serialize-javascript`:如果其輸出的字串被 `eval()` 執行,則極度危險。其設計目的通常是安全的內嵌到 HTML 中,但誤用會導致問題。 * **不安全的物件合併/克隆:** 有些函式庫或自訂程式碼在反序列化(或類似操作如深層複製)時,可能會遞迴地合併物件屬性,這可能導致**原型污染 (Prototype Pollution)** 漏洞,進而可能間接導致 RCE 或其他安全問題。 * **自訂序列化格式:** 應用程式可能實現了自己的序列化/反序列化邏輯,需要具體分析其安全性。 * **識別方法:** * 程式碼審查:搜索已知不安全的函式庫如 `node-serialize`。尋找 `eval()` 是否處理了來自外部的、看起來像序列化資料的輸入。審查物件合併、克隆相關的程式碼,特別是處理使用者輸入的部分,檢查是否存在原型污染的可能。 * 動態測試:尋找特定的序列化格式(如 `node-serialize` 的 `{"rce":"_$$ND_FUNC$$_function (){...}()"}`)。測試原型污染 Payload(如 `{"__proto__":{"polluted":"yes"}}`)看是否能影響全域 `Object.prototype`。 ### Ruby * **危險函數/類別:** * `Marshal.load()`, `Marshal.restore()`:Ruby 原生的反序列化方法,處理二進位格式,非常危險。 * `YAML.load()`:Ruby 標準庫中的 YAML 解析器,類似 Python 的 `PyYAML`,可以直接實例化任意類別,甚至執行程式碼。 * `PStore`:基於 `Marshal` 的持久化儲存。 * **資料格式特徵:** * `Marshal`: 二進位格式,Base64 編碼後可能包含 `\x04\x08` (版本標識)。 * `YAML`: 標準 YAML 格式,可包含 `!ruby/object:` 等標籤來指定 Ruby 物件。 * **識別方法:** * 程式碼審查:搜索 `Marshal.load`, `Marshal.restore`, `YAML.load` (注意不是 `YAML.safe_load`)。 * 動態測試:尋找 `Marshal` 或 YAML 格式的資料。構造利用 Gadget Chains 的 `Marshal` Payload(需要了解目標應用的依賴)或利用 `YAML.load` 執行命令的 Payload(如 `!ruby/object:Gem::Installer {}\n command: calc`)。 * **安全建議:** 強烈建議使用 `YAML.safe_load()` 替代 `YAML.load()`。絕對避免對不可信來源的資料使用 `Marshal.load`。 ## 檢測時關注的跡象 ### Base64 編碼的長字串 * **特徵:** 由 `A-Z`, `a-z`, `0-9`, `+`, `/` 組成,結尾可能有 `=` 或 `==` 作為填充。字串通常很長。 * **常見位置:** * HTTP Cookie 值 (例如 `session`, `user_prefs`, `remember_me`) * HTTP Header (例如 `Authorization`, 自訂 Header) * POST/PUT 請求的 Body * URL 參數 (雖然較少見,但也可能) * 表單欄位值 (特別是隱藏欄位) * **為何可疑:** 二進位的序列化資料(如 Java、.NET BinaryFormatter、Ruby Marshal、Python Pickle)經常被 Base64 編碼後透過 HTTP 傳輸。 * **下一步:** * 嘗試 Base64 解碼。 * **檢查解碼後的開頭字節:** * `aced` (十六進位) 或 `rO0` (Base64 開頭): 強烈暗示 **Java** 序列化。 * `\x04\x08` (十六進位) 或 `BAg=` (Base64 開頭): 可能暗示 **Ruby Marshal**。 * 其他二進位格式可能沒有這麼明顯的標記,但長度本身就值得懷疑。 * 使用 `ysoserial`, `ysoserial.net` 等工具嘗試生成對應語言的 Payload 並替換原始字串進行測試。 ### PHP 序列化格式字串 * **特徵:** 人類可讀的文字格式,包含特定標記: * `O:[數字]:"`:表示一個物件 (Object)。例如 `O:8:"UserInfo":2:{...}` * `a:[數字]:{`:表示一個陣列 (Array)。例如 `a:3:{i:0;s:4:"test";...}` * `s:[數字]:"`:表示一個字串 (String)。例如 `s:4:"name";` * `i:[數字];`:表示一個整數 (Integer)。 * `b:[0或1];`:表示一個布林 (Boolean)。 * `N;`:表示 NULL。 * **常見位置:** * HTTP Cookie 值 * POST 請求參數 * 資料庫中儲存的設定或 Session 資料 * **為何可疑:** 這是 PHP `serialize()` 函數的輸出,如果傳遞給 `unserialize()` 且來源可控,就可能觸發漏洞。 * **下一步:** * 檢查字串來源是否可控。 * 使用 `PHPGGC` 工具生成 Payload 進行測試。 ### JSON 字串中包含類型指示符 * **特徵:** 看似普通的 JSON,但其中包含特殊的鍵值對,用來指定反序列化時應該使用的類別。 * `"$type": "Namespace.ClassName, AssemblyName"`:常見於 **.NET (Newtonsoft.Json)** 配置不當時。 * `"@type": "com.example.SomeClass"`:常見於 **Java (Jackson, Fastjson)** 配置不當時。 * `"__type": "Namespace.ClassName, AssemblyName"`:常見於 **.NET (JavaScriptSerializer)** 配置不當時。 * **常見位置:** * API 請求的 JSON Body * 儲存在客戶端(如 LocalStorage)或傳輸的 JSON 設定 * **為何可疑:** 允許客戶端指定服務器端要實例化的類別,是反序列化漏洞的典型入口。 * **下一步:** * 嘗試修改 `"$type"` 或 `@type` 的值,指向已知的 Gadget Chain 類別(如 .NET 的 `ObjectDataProvider`)。 * 使用 Burp Suite 的 Scanner 或相關擴充功能檢測。 ### XML 字串中包含可疑標籤或屬性 * **特徵:** XML 格式的資料中出現可能用於指定物件類別或執行程式碼的標籤。 * `<object class="java.lang.ProcessBuilder">...</object>`:**Java XMLDecoder** 的危險信號。 * `<__type>Some.Class.Name</__type>` 或 `z:Type="Some.Class.Name"` (配合特定命名空間): 可能用於 **.NET (DataContractSerializer)**。 * 直接使用類別名稱作為標籤:例如 `<com.example.Data>...</com.example.Data>` (可能用於 Java XStream)。 * **常見位置:** * SOAP 請求 * XML-RPC 請求 * SAML Assertion * 設定檔上傳或交換 * **為何可疑:** XML 反序列化器如果配置不當,允許從 XML 結構中確定要實例化的類別。 * **下一步:** * 嘗試修改 class 屬性或類型標籤,指向 Gadget Chain。 * 檢查是否使用了已知的易受攻擊 XML 解析器(XMLDecoder, XStream 等)。 ### YAML 字串中包含特殊標籤 * **特徵:** YAML 格式的資料中包含 `!!python/`、`!ruby/object:` 等語言特定的標籤,或者像 `!!javax.script.ScriptEngineManager [...]` (Java SnakeYAML RCE) 這樣的危險標籤。 * `!!python/object/apply:os.system ["command"]` * `!ruby/object:Gem::Installer {}\n command: calc` * **常見位置:** * 設定檔 * API 請求 Body (如果接受 YAML) * **為何可疑:** 某些 YAML 解析器(如舊版 PyYAML, Ruby YAML.load)允許執行任意程式碼或實例化任意物件。 * **下一步:** * 嘗試注入惡意 YAML 標籤。 * 檢查是否使用了 `yaml.load()` (Python/Ruby) 而不是 `yaml.safe_load()`。 ### ASP.NET 特有的參數 * **特徵:** 在 HTML 表單中看到名為 `__VIEWSTATE` 的隱藏欄位,其值通常是一長串 Base64 字串。可能伴隨 `__VIEWSTATEGENERATOR` 和 `__EVENTVALIDATION`。 * **常見位置:** ASP.NET Web Forms 頁面的 POST 請求中。 * **為何可疑:** ViewState 是 ASP.NET Web Forms 用來儲存頁面和控制項狀態的機制,它本身就是序列化的資料。如果 ViewState 沒有使用強金鑰進行 MAC 校驗(或金鑰洩漏)且未加密,攻擊者可以偽造 ViewState 來觸發伺服器端的反序列化漏洞 (通常利用 `ObjectStateFormatter` 或 `LosFormatter`)。 * **下一步:** * 使用 `ysoserial.net` 生成針對 ViewState 的 Payload。 * 使用 Burp Suite 的 ViewState Editor 等工具分析和修改 ViewState。