1.DataContractJsonSerializer的基本使用
又是DataContract字辈的,在基本使用上和以前介绍过的几个DataContract序列化与反序列化是基本一致的,但这玩意是用于JSON格式数据的序列化与反序列化的。使用Y4er师傅的演示demo来学习
首先一样的,还是对想要序列化的类加上DataContract特性(同样支持Serializable特性),属性加上DataMember特性,然后再来看看序列化与反序列化流程:
这里还是要注意Type是否可控以及ReadObject()接受的内容是否可控,如果都可控则存在反序列化问题。来试验一下:
可以成功序列化与反序列化。那么我们要怎么攻击呢?
2.DataContractJsonSerializer反序列化安全问题
这里再介绍DataContractJsonSerializer的一个有趣用法,参考微软文档:
https://learn.microsoft.com/zh-cn/dotnet/framework/wcf/feature-details/stand-alone-json-serialization
也就是说,在序列化的json数据中可以加入一个__type键,后面可以指定命名空间+类名,看到这立马又给人一种Fastjson的既视感了,这个__type不就相当于@type吗?Ysoserial.net生成一个payload看看。
可以看见,这里指定
System.Security.Principal.WindowsPrincipal
并且给其m_identity赋值,这个详情可以看之前的WindowsPrincipal反序列化链分析
当Type可控的情况下,使用上述payload即可触发链子
还有几种即使Type不可控也能利用的情况,一种是使用了KnownType特性指定了WindowsPrincipal,来学习一下
如图,正常情况下,type不可控的话就没办法反序列化了,然而如果在Person类上方加一个特性
[KnownType(typeof(WindowsPrincipal))]
就可以正常反序列化WindowsPrincipal类的对象
此时可以成功RCE,但是正常开发者估计很少使用这玩意,就算用了大概率也不会指定WindowsPrincipal,除此之外还有一个方法可以指定KnownType:
最后一个参数可以指定List<Type>类型,其中可以存放Type,可以关注一下如果这个List可控,那么也相当于Type可控:
这个相比上面那种KnownType的用法来说,还是比较可能遇到。
除此之外Type不可控的情况下还有一种情况可以导致间接可控,就是利用
IDataContractSurrogate
这个机制甚至可以导致一些没有DataContract特性或Serializable特性的类参与序列化与反序列化
先写出三个类,Person类中的dog字段接受Dog类的对象,而Dog类又没有[DataContract]特性
然后这个DogSurrogated在我理解中算是后面用于存储Dog信息的一个中间人。
接下来写一个继承IDataContractSurrogate的类
在其中实现
GetDataContractType()
这个方法主要用于判断Type,如果是Dog,会自动返回
DogSurrogated Type
接着在GetObjectToSerialize方法中,会把Dog类的对象转化成XML格式的序列化数据
在GetDeserializedObject方法中,又会对XML格式的数据进行反序列化:
然后要怎么使用这个DogSurrogate类呢,看下图的演示
DataContractJsonSerializer
在上述构造方法调用的时候将其传入即可
来看看效果:
可以看到,原本应该不能正常序列化与反序列化的Dog类的对象,现在转化成了xml格式数据,后续也可以正常反序列化,如果目标在GetDeserializedObject中实现了别的反序列化操作,比如使用我们之前学习过的几个经典反序列化点,有很大概率会造成安全问题。
关于IDataContractSurrogate更详细的demo和分析可以参考Y4er师傅的文章
https://xz.aliyun.com/t/9601