原文來自安全客,作者:Ivan1ee@360云影實驗室
原文鏈接:https://www.anquanke.com/post/id/176499

相關閱讀:

0x00 前言

SoapFormatter格式化器和下節課介紹的BinaryFormatter格式化器都是.NET內部實現的序列化功能的類,SoapFormatter直接派生自System.Object,位于命名空間System.Runtime.Serialization.Formatters.Soap,并實現IRemotingFormatter、IFormatter接口,用于將對象圖持久化為一個SOAP流,SOAP是基于XML的簡易協議,讓應用程序在HTTP上進行信息交換用的。但在某些場景下處理了不安全的SOAP流會造成反序列化漏洞從而實現遠程RCE攻擊,本文筆者從原理和代碼審計的視角做了相關介紹和復現。

0x01 SoapFormatter序列化

SoapFormatter類實現的IFormatter接口中定義了核心的Serialize方法可以非常方便的實現.NET對象與SOAP流之間的轉換,可以將數據保存為XML文件,官方提供了兩個構造方法。

img

下面還是用老案例來說明問題,首先定義TestClass對象

img

定義了三個成員,并實現了一個靜態方法ClassMethod啟動進程。 序列化通過創建對象實例分別給成員賦值

img

常規下使用Serialize得到序列化后的SOAP流,通過使用XML命名空間來持久化原始程序集,例如下圖TestClass類的開始元素使用生成的xmlns進行限定,關注a1 命名空間

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<SOAP-ENV:Body>

<a1:TestClass id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/WpfApp1/WpfApp1%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">

<classname id="ref-3">360</classname>

<name id="ref-4">Ivan1ee</name>

<age>18</age>

</a1:TestClass>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

0x02 SoapFormatter反序列化

2.1、反序列化用法

SoapFormatter類反序列化過程是將SOAP消息流轉換為對象,通過創建一個新對象的方式調用Deserialize多個重載方法實現的,查看定義得知實現了IRemotingFormatter、IFormatter接口,

img

查看IRemotingFormatter接口定義得知也是繼承了IFormatter

img

筆者通過創建新對象的方式調用Deserialize方法實現的具體實現代碼可參考以下

img

反序列化后得到TestClass類的成員Name的值。

img

2.2、攻擊向量—ActivitySurrogateSelector

在SoapFormatter類的定義中除了構造函數外,還有一個SurrogateSelector屬性, SurrogateSelector便是代理選擇器,序列化代理的好處在于一旦格式化器要對現有類型的實例進行反序列化,就調用由代理對象自定義的方法。查看得知實現了ISurrogateSelector接口,定義如下

img

因為序列化代理類型必須實現System.Runtime.Serialization.ISerializationSurrogate接口,ISerializationSurrogate在Framework Class Library里的定義如下:

img

圖中的GetObjectData方法在對象序列化時進行調用,目的將值添加到SerializationInfo集合里,而SetObjectData方法用于反序列化,調用這個方法的時候需要傳遞一個SerializationInfo對象引用,換句話說就是使用SoapFormatter類的Serialize方法的時候會調用GetObjectData方法,使用Deserialize會調用SetObjectData方法。SoapFormatter類還有一個非常重要的屬性SurrogateSelector,定義如下

img

在序列化對象的時候如果屬性SurrogateSelector屬性的值非NULL便會以這個對象的類型為參數調用其GetSurrogate方法,如果此方法返回一個有效的對象ISerializationSurrogate,這個對象對找到的類型進行反序列化,這里就是一個關鍵的地方,我們要做的就是實現重寫ISerializationSurrogate調用自定義代碼,如下Demo

img

代碼中判斷類型解析器IsSerializable屬性是否可用,如果可用直接基類返回,如果不可用就獲取派生類 System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector的類型,然后交給Activator創建實例

再回到GetObjectData方法體內,另外為了對序列化數據進行完全控制,就需要實現Serialization.ISeralizable接口,定義如下:

img

有關更多的介紹請參考《.NET高級代碼審計第二課 Json.Net反序列化漏洞》,在實現自定義反序列類的時通過構造方法讀取攻擊者提供的PocClass類

img

下圖定義了PayloadClass類實現ISerializable接口,然后在GetObjectData方法里又聲明泛型List集合接收byte類型的數據

img

將PocClass對象添加到List集合,聲明泛型使用IEnumerable集合map_type接收程序集反射得到的Type并返回IEnumerable類型,最后用Activator.CreateInstance創建實例保存到 e3此時是一個枚舉集合的迭代器。

img

上圖將變量e3填充到了分頁控件數據源,查看PageDataSource類定義一目了然,

img

除此之外System.Runtime.Remoting.Channels.AggregateDictionary返回的類型支持IDictionary,然后實例化對象DesignerVerb并隨意賦值,此類主要為了配合填充MenuCommand類properties屬性的值,最后為哈希表中的符合條件的buckets賦值。

img

接下來用集合添加數據源DataSet,DataSet和DataTable對象繼承自System.ComponentModel.MarshalByValueComponent類,可序列化數據并支持遠程處理ISerializable接口,這是ADO.NET對象中僅有支持遠程處理的對象,并以二進制格式進行持久化。

img

更改屬性DataSet.RemotingFormat值為SerializationFormat.Binary,更改屬性DataSet.CaseSensitive為false等,再調用BinaryFormatter序列化List集合,如下圖。

img

因為指定了RemotingFormat屬性為Binary,所以引入了BinaryFormatter格式化器并指定屬性SurrogateSelector代理器為自定義的MySurrogateSelector類。序列化后得到SOAP-XML,再利用SoapFormatter對象的Deserialize方法解析讀取文件內容的流數據,成功彈出計算器

img

img

img

2.3、攻擊向量—PSObject

由于筆者的Windows主機打過了CVE-2017-8565(Windows PowerShell遠程代碼執行漏洞)的補丁,利用不成功,所以在這里不做深入探討,有興趣的朋友可以自行研究。有關于補丁的詳細信息參考:

https://support.microsoft.com/zh-cn/help/4025872/windows-powershell-remote-code-execution-vulnerability

0x03 代碼審計視角

3.1、XML載入

從代碼審計的角度找到漏洞的EntryPoint,傳入XML,就可以被反序列化,這種方式也是很常見的,需要關注一下,LoadXml直接載入xml數據,這個點也可以造成XXE漏洞。例如這段代碼:

img

這種污染點漏洞攻擊成本很低,攻擊者只需要控制傳入字符串參數source便可輕松實現反序列化漏洞攻擊,彈出計算器。

img

3.2、File讀取

img

這段是摘自某個應用的代碼片段,在審計的時候只需要關注DeserializeSOAP方法中傳入的path變量是否可控。

0x04 總結

實際開發中SoapFormatter 類從.NET Framework 2.0開始,這個類已經漸漸過時了,開發者選擇它的概率也越來越少,官方注明用BinaryFormatter來替代它,下篇筆者接著來介紹BinaryFormatter反序列化漏洞。最后.NET反序列化系列課程筆者會同步到 https://github.com/Ivan1ee/https://ivan1ee.gitbook.io/ ,后續筆者將陸續推出高質量的.NET反序列化漏洞文章,歡迎大伙持續關注,交流,更多的.NET安全和技巧可關注實驗室公眾號。


本文經安全客授權發布,轉載請聯系安全客平臺。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/891/