1.DataContractSerializer的使用
一个功能和用法都很像XmlSerializer的方法。先用软子的官方文档的代码来学习一下。我们先写一个类
注意这个类上面要加上[DataContract()]特性,类的属性加上[DataMember()]特性
接着我们写出ReadObject()和WriteObject()方法,前者用于反序列化,后者用于序列化。可以看到关键的代码其实在:
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
// Deserialize the data and read it from the instance.
Person deserializedPerson = (Person)ser.ReadObject(reader, true);
一样需要指定Type,通过调用DataContractSerializer类的ReadObject()方法,对内容进行反序列化,而内容通过XmlDictionaryReader类对XML数据处理的来,这个类我们在前面简单介绍过。
然后在Main函数里运行上述函数
可以看到,在使用上,和XmlSerializer非常类似,只要type可控,并且XML内容可控,就是一个反序列漏洞点了。那么它的序列化与反序列化是什么样的呢?运行代码:
确实成功序列化与反序列化了,最后得到的序列化内容如下:
此外这个方法除了接受[DataContract()]特性,还接受[Serializable]特性
如图,标上[Serializable]特性,后续一样可以正常序列化与反序列化
所以这个点吧,很有意思,它既可以走XmlSerializer的ObjectDataProvider链,其它和Formatter有关的链子它也能用上。
审计上关注DataContractSerializer的readObject方法接受的内容是否可控,不过也要关注Type是否可控(后续我们还会学习一些特殊情况)
关于ObjectDataProvider之前学习过了,Y4er用的演示代码是这样的:
从XML的root节点读取type,其他部分作为内容传入ReadObject()方法进行反序列化。Type和内容都可控的情况下就是一个反序列化漏洞点,生成一个ObjectDataProvider链子去打就行,可以成功弹计算器:
2.SessionViewStateHistoryItem链
我们也来跟着分析一下这个链
这个类是
System.Web.UI.MobileControls.SessionViewState
类的一个内部类,其反序列化构造方法从info里取出s变量的值并对其进行LosFormatter反序列化,简单粗暴。
3.Type可控的特殊情况之DataContractResolver
通过对DataContractSerializer构造方法中传入DataContractResolver(数据契约解析器),在部分Type不可控的场景下也可以实现反序列化。还是借用Y4er的demo
这里先写一个MyClass类,其中有一个object类型的属性
接下来是序列化与反序列化。这里注意,objectDataProvider的ObjectInstance属性的值是ProcessClass类的对象,最后再把objectDataProvider赋值给MyClass类的o属性。
在接下来是指定typeof为Myclass,这个Type我们不能控制,正常来说是没办法实现反序列化攻击的,但是这里MyClass类中有一个object类型属性,并且这里构造方法传入了MyDataContractResolver()
简单来说这玩意就相当于对DataContractResolver的附魔
在序列化时,当 DataContractSerializer 需要将 MyClass 中的 object 类型的成员 o(即 ObjectDataProvider)转换为 XML 时,它会调用 TryResolveType 方法来获取类型的名称和命名空间。
在反序列化时,当从 XML 中读取对象时,ResolveName 方法会被调用,以根据 XML 中的类型信息找到相应的 .NET 类型。这是非常重要的,因为如果 XML 中的类型信息无法被解析,反序列化将会失败。
所以,在部分type不可控的情况下,如果使用了DataContractResolver,且其中有额外的对Type的处理机制,那么还是可以RCE的。最后可以借助这个机制生成一个序列化payload
然后要修改一下ObjectInstance的type类型并加上__identity
上述这个问题其实就是Exchange 反序列化漏洞 CVE-2021-28482 的成因,并且我们可以注意到在上述这种情况下,不再需要ExpandedWrapper进行包装。ExpandedWrapper的使用场景是在type可控时,告知多个类型。而上述场景中类型会在DataContractResolver中获取好,就不需要包装了。
此外除了这种情况,还有一种情况就是在序列化的类上面加了KnownType特性:
[KnownType(typeof(WindowsPrincipal))]
不过这个在实战审计中估计很难遇到,看起来都有点类似后门的写法。总之关于KnowType特性,还有别的几个涉及Type的操作在以后的几个DataContract相关的反序列化点中会慢慢学习。
4.参考
https://xz.aliyun.com/t/9599
https://www.freebuf.com/articles/web/199740.html
https://www.freebuf.com/articles/web/272564.html
https://xz.aliyun.com/t/9601