CVE-2021-42321-天府杯Exchange 反序列化漏洞分析
漏洞信息
今年天府杯爆出了一個新的Exchange 遠程命令執行漏洞,最近網上相關細節被披露,在此基礎上本文對該漏洞進行了詳細分析和復現。
- 漏洞編號:CVE-2021-42321
- 漏洞類型:遠程命令執行
- 前提條件:郵箱賬號認證
經過分析,發現該漏洞是一個反序列化漏洞,適用版本范圍如下:
- Exchange 2019 CU10, 11
- Exchange 2016 CU21, 22
環境搭建
安裝Exchange2016 CU21。

添加域用戶,并在Exchange管理中心添加普通用戶。

補丁對比
根據官方文檔下載補丁更新文件,下載后補丁文件為`Exchange2016-KB5007409-x64-en.msp`。

使用Uniextract軟件提取補丁文件,改動文件有1083個,其中dll文件有800多個。

接下來使用dnspy反編譯dll文件,和CU21進行對比。

補丁中代碼的修改量是非常大的,經過長時間分析,定位到`Microsoft.Exchange.Compliance`下`TypedBinaryFormatter`代碼被刪除。

查看`TypedBinaryFormatter`發現調用DeserializeObject函數時并未使用binder參數,存在安全問題。`SerializatinBinder`是一個抽象類,用于控制反序列化的類型,防止安全問題發生。

對`TypedBinaryFormatter`進行測試,可以觸發命令執行:

調用鏈分析
接下來需要定位反序列化函數的調用點。使用Dnspy分析功能可以快速分析函數和類的引用關系,發現`ClientExtensionCollectionFormatter.Deserialize`調用了`TypedBinaryFormatter.Deserialize`。

`ClientExtensionCollectionFormatter`類是`IClientExtensionCollectionFormatter`的接口實現,在`OrgExtensionSerializer.TryDeserialize()`被調用。

而`TryDeserialize`讀取`userConfiguration`配置并反序列化。

使用`UserConfiguration`等關鍵字查閱官方文檔,`CreateUserConfiguration`接口可遠程設置用戶選項,但文檔中并沒有反序列化類型數據(BinaryData)的設置方法。

使用Dnspy搜索`CreateUserConfiguration`方法,找到如下調用關系。`SetStream`函數解析數據的對象格式為`ServiceUserConfiguration`。
CreateUserConfiguration.Execute()UserConfigurationCommandBase.SetProperties()UserConfigurationCommandBase.SetStream()

查看`SeviceUserConfiguration`定義,它同時包含`DictionaryEntry`和`BinaryData`字段。

那么如果要插入BinaryData數據,只需在數據中``同級目錄添加``即可。經測試需使用`FolderID`替換`DistinguishedFolderId`,否則添加數據失敗。FolderId可以通過`GetFolder`接口獲取。

觸發反序列化
通過公開文檔查閱,找到了`GetClientAccessToken`接口可以觸發`OrgExtensionSerializer.TryDeserialize`:

分析一下調用過程。在`GetClientAccessToken.PrepareForExtensionRelatedTokens`中調用`GetUserExtensionDataList`和`GetUserExtensionDataListWithoutUpdatingCache`。


隨后在`GetExtensibilityContext`中執行`GetExtensions`。

接下來進入`InstalledExtensionTable`,在`GetOrgExtensionDataGetter`函數中調用`OrgExtensionTable.GetOrgExtensions`。

繼續調用`GetAllOrgExtensionData`方法。

在`OrgExtensionDataGetter`中執行`Retrieve`。

`CachedOrgExtensionRetriever`為`IOrgExtensionRetriever`接口的一個實現,其`Retrieve`函數調用`TryDeserializeExtensionFromCache`。

最終執行`TryDeserialize`進行反序列化。

結合插入的反序列化數據可執行命令。

這里附上一個調試堆棧截圖。
