1.JavaScriptSerializer基础使用
这也是一个用于json序列化与反序列化的类,学习一下使用。先写一个用于测试的类,注意这个类可以不用打上Serializable特性
序列化与反序列化流程如下:
运行一下代码。可以看到,序列化后产生的数据是
{"Name":"test"}
并且在反序列化过程中,会依次触发Person类的构造方法,以及对应属性的set方法。推测JavaScriptSerializer的底层是用反射实现的
2.JavaScriptSerializer反序列化安全问题
既然可能是用反射实现,那感觉危害程度会比较高。那么它有没有类似__type或者@type这样的特性去指定反序列化的类呢?在文档里下面几条有一个
SimpleTypeResolver
微软专门给了警告说它可能会造成反序列化问题,可能这就是我们要找的东西了
看看微软给出的不安全代码演示嗷,可以看到在调用JavaScriptSerializer构造方法的时候,传入了SimpleTypeResolver类的对象,后续反序列化的时候还是个泛型
第二个不安全代码演示如下:
虽然没有使用Deserialize泛型,但是使用了SimpleTypeResolver,仍然存在反序列化漏洞。我们来试试看,我们也加一个SimpleTypeResolver
注意此时生成的数据:
{"__type":"JavaScriptDeserialize.Person, ConsoleApp3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"test"}
好家伙,__type这么指定是吧,你比fastjson还NB啊。那我们搓链子其实很容易,直接按格式做一个恶意ObjectDataProvider类的对象即可
运行,成功RCE
这个过程都很好理解,还是从代码上去看看为什么。
跟进BasicDeserialize(),这里把传参送到JavaScriptObjectDeserializer类构造方法里包装了一下,然后调用这个类的DeserializeInternal方法
构造方法主要是做一些类的初始化(重要的序列化数据被赋值给_s属性了)
继续跟进DeserializeInternal()方法,这里判断json数据里是否有__type键,有则进入ConvertObjectToType方法
又进入ConvertObjectToTypeMain方法
这里会把o(前面包含__type信息的dictionary变量)传入ConvertObjectToTypeInternal方法
跟进ConvertObjectToTypeInternal,又把dictionary传入ConvertDictionaryToObject方法
这个方法里有三步比较重要,先从dictionary里取出__type的值,然后赋值给obj2.接着给obj2赋值给text,再接着把text传入ResolveType()方法
而这个ResolveType()方法实际上是SimpleTypeResolver类中的同名方法:
可以看到,这个方法把传入字符进一步传入GetType()方法,也就是说这里直接获取到我们传入的__type的Type对象,也即此时的type2
再往后,这里对type2调用Activator.CreateInstance()方法,即可创造目标类的对象
因此,目标使用SimpleTypeResolver这个条件非常关键,或者如果目标自实现了TypeResolver,且其ResolveType()写法也是直接Type.GetType()的话,也有漏洞。实战审计中主要关注是否有类似下面这样的代码:
JavaScriptSerializer()构造方法里传入
new SimpleTypeResolver()
且Deserialize()接受的json数据可控,则存在反序列化漏洞。然后如果你看到Deserialize()方法里的type传参不可控,比如下面这样:
别担心,这不影响我们进行反序列化攻击
3.参考
https://xz.aliyun.com/t/9602
原文始发于微信公众号(HW专项行动小组):10.JavaScriptSerializer反序列化点
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论