NetDataContractSerializer和DataContractSerializer一樣用於序列化和反序列化Windows Communication Foundation (WCF) 訊息中發送的資料。兩者之間存在一個重要區別:NetDataContractSerializer 包含了CLR,透過CLR類型添加額外資訊並保存引用來支援類型精確,而DataContractSerializer 則不包含。因此,只有在序列化和反序列化端使用相同的 CLR 類型時,才能使用 NetDataContractSerializer。若要序列化物件使用 WriteObject或Serialize方法, 若要反序列化 XML流使用 ReadObject或Deserialize方法。在某些場景下讀取了惡意的XML流就會造成反序列化漏洞,從而實現遠端RCE攻擊,本文筆者從原理和程式碼審計的視角做了相關介紹和復現。
SoapFormatter類別實現的IFormatter介面中定義了核心的Serialize方法可以非常方便的實現.NET物件與SOAP流之間的轉換,可以將資料保存為XML文件,官方提供了兩種建構方法。
下面還是用舊案例來說明問題,先定義TestClass物件
定義了三個成員,並且實作了一個靜態方法ClassMethod啟動進程。序列化透過建立物件實例分別給成員賦值
#常規下使用Serialize得到序列化後的SOAP流,透過使用XML命名空間來持久化原始程式集,例如下圖TestClass類別的開始元素使用產生的xmlns進行限定,關注a1 命名空間
<envelope> <body> <testclass> <classname>360</classname> <name>Ivan1ee</name> <age>18</age> </testclass> </body> </envelope>
SoapFormatter類別反序列化過程是將SOAP訊息流轉換為對象,透過創建一個新對象的方式調用Deserialize多個重載方法實現的,查看定義得知實現了IRemotingFormatter、IFormatter接口,
查看IRemotingFormatter介面定義得知也是繼承了IFormatter
筆者透過建立新物件的方式來呼叫Deserialize方法實現的具體實作程式碼可參考以下
反序列化後得到TestClass類別的成員Name的值。
在SoapFormatter類別的定義中除了建構子外,還有一個SurrogateSelector屬性,SurrogateSelector便是代理選擇器,序列化代理的好處是一旦格式化器要對現有類型的實例進行反序列化,就呼叫由代理物件自訂的方法。查看得知實作了ISurrogateSelector接口,定義如下
因為序列化代理類型必須實作System.Runtime.Serialization.ISerializationSurrogate接口,ISerializationSurrogate在Framework ClassLibrary裡的定義如下:
下圖定義了PayloadClass類別實作ISerializable接口,然後在GetObjectData方法又宣告泛型List集合接收byte類型的資料
#將PocClass物件加入List集合,宣告泛型使用IEnumerable集合map_type接收組件反射得到的Type並傳回IEnumerable類型,最後用Activator.CreateInstance建立實例儲存到e3此時是一個枚舉集合的迭代器。
上圖將變數e3填入了分頁控制資料來源,檢視PageDataSource類別定義一目了然,
#除此以外System.Runtime.Remoting.Channels.AggregateDictionary回傳的類型支援IDictionary,然後實例化物件DesignerVerb並隨意賦值,此類主要為了配合填充MenuCommand類別properties屬性的值,最後為哈希表中的符合條件的buckets賦值。
接下來以集合新增資料來源DataSet,DataSet與DataTable物件繼承自System.ComponentModel.MarshalByValueComponent類,可序列化資料並支援遠端處理ISerializable介面,這是ADO.NET物件中僅有支援遠端處理的對象,並以二進位格式進行持久化。
更改屬性DataSet.RemotingFormat值為SerializationFormat.Binary,更改屬性DataSet.CaseSensitive為false等,再呼叫BinaryFormatter序列化List集合,如下圖。
因為指定了RemotingFormat屬性為Binary,所以引入了BinaryFormatter格式化器並指定屬性SurrogateSelector代理程式為自訂的MySurrogateSelector類別。序列化後得到SOAP-XML,再利用SoapFormatter物件的Deserialize方法解析讀取檔案內容的流數據,成功彈出計算器
由於筆者的Windows主機打過了CVE-2017-8565(Windows PowerShell遠端程式碼執行漏洞)的補丁,利用不成功,所以在這裡不做深入探討,有興趣的朋友可以自行研究。有關補丁的詳細資訊參考:https://support.microsoft.com/zh-cn/help/4025872/windows-powershell-remote-code-execution-vulnerability
四、程式碼審計
######4.1 ######XML載入#########從程式碼審計的角度找到漏洞的EntryPoint,傳入XML,就可以被反序列化,這種方式也是很常見的,需要注意一下,LoadXml直接載入xml數據,這個點也可以造成XXE漏洞。例如這段程式碼: ##################這種污染點漏洞攻擊成本很低,攻擊者只需要控制傳入字串參數source便可輕鬆實現反序列化漏洞攻擊,彈出計算器。 ###############4.2 File讀取################這段是摘自某個應用程式的程式碼片段,在審計的時候只需要關注DeserializeSOAP方法中傳入的path變數是否可控。 ###以上是SoapFormatter反序列化漏洞範例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!