8.NetDataContractSerializer反序列化点以及PSObject链

2024-10-21 12:07   广东  

1.NetDataContractSerializer使用

基本上来说和之前学习的

DataContractSerializer

区别不大,一个比较重要的区别就是NetDataContractSerializer进行序列化的时候会在内容里加上CLR类型信息,序列化与反序列化时的CLR类型信息要对应上。

这里依旧是使用[DataContract()]特性和[DataMember()]特性去标注我们想要序列化的类,当然也支持[Serializable]特性。

接着是官方给出的序列化与反序列化的写法

值得注意的是,这里官方演示反序列化的时候,

NetDataContractSerializer()

方法里并没有指定Type类型,开发者说不定也会这么写

是否意味着审计这个反序列化点的时候不用像以前一样那么关心Type是否可控,毕竟软子也干了。

总之尝试进行一下序列化与反序列化:

看看序列化数据

主要就是红框标注的部分,Type就是Person类的Type,Assembly是ConsoleApp3。所以这个利用也相对简单,可以用很多我们学过的链子去打,比如TextFormattingRunProperties

ysoserial.exe -f NetDataContractSerializer -g TextFormattingRunProperties -c "calc.exe" -o raw

替换原先的xml文件内容,运行反序列化流程:

成功rce。


2.PSObject链

Y4er师傅是把NetDataContractSerializer和PSObject链放一块讲的,这里我也学习一波。前排提示,这个链子前面的部分很长,这里主要分析最后的sink点的逻辑(补充一下师傅们没细写的地方),搞清楚Sink点之后就是一路往上跟到反序列化构造方法,先定位到

FigureParseConversion()

FigureParseConversion方法,其中有一段代码,对传入的type调用GetMethod,也即这里可以反射获取目标类的Parse方法,该方法接受一个String类型传参

因此我们可以想到反射调用XamlReader的Parse()方法去进行RCE,刚好满足条件。但是这里只拿到Method没用,毕竟还没调用呢。所以继续往后看,这里最后return的时候,实例化

ConvertViaParseMethod

并且将ConvertWithoutCulture方法传入PSConverter()(委托)

而ConvertWithoutCulture其中调用了Invoke,若其传参的valueToConvert可控则可以rce,valueToConvert来自ConvertWithoutCulture的参数

也即

FigureParseConversion(fromType, toType)

方法最后调用得到一个委托,我们追踪一下FigureParseConversion的调用,可以找到

FigureConversion()

fromType和toType来自FigureConversion()的参数,理论上Type可控,可以控制为XamlRead

那么Parse()的参数是否可控就显得很重要,前面分析过Parse()的参数来自

ConvertWithoutCulture()

的传参,也即上面提到的委托,如图,这里赋值给了psconverter变量,现在psconverter就等于ConvertWithoutCulture()的委托

因此,如果我们能找到形如psconverter()的调用就好了,继续跟踪psconverter,看到最后这里的return,传入CacheConversion

又传入ConversionData

其中给本类的converter属性赋值,此时这个属性就相当于委托,跟踪一下converter,可以看到在ConversionData里有一个Invoke的方法,恰好就是converter()的类型,并且参数一个都没落。

OK现在我们知道,FigureConversion方法中的FigureParseConversion方法的一个重要作用其实是给ConversionData类中的converter属性赋值(一个关键的委托),而这个类中还有一个Invoke方法,可以执行委托。

因此我们再尝试再找一下Invoke()的调用,最好是和FigureConversion安排到一起的

这里找到一个ConvertTo()方法,可以看到,刚好就是

FigureConversion+Invoke

赋值完后马上执行,且所有关键传参都来自ConvertTo()方法的传参,都可控

我们这里是从sink点一路找调用,后续就是一路往上跟ConvertTo的调用就行,最后可以跟到PSObject类的反序列化构造函数,这里直接给出Y4er师傅本地调试的调用堆栈

后半段就是我们分析的点,前半段就是一路跟调用,一路想办法给一些属性赋值就行。


3.总结

NetDataContractSerializer

DataContractSerializer

很像,在没有指定type的情况下,只需要关注反序列化时传入readObject()方法的内容是否可控。

此外还分析了PSObject链的后半段,又是一个涉及XamlReader.Parse()以及委托的sink点,还是很有意思的。


4.参考

https://xz.aliyun.com/t/9600

HW专项行动小组
大师!教我打攻防
 最新文章