目录
前言
CC6的失效——LazyMap之殇
Rome-TemplatesImpl链的失效——transient之殇
结语
前文:【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识
【Web】浅聊Hessian反序列化之打Rome出网&不出网
前言
注意到很多 Java 原生反序列化利用链在 Hessian 中无法使用,甚至 ysoserial 中一些明明是 hashCode/equals/compareTo 触发的链子都不能直接拿来用。这是为什么呢?本文将以下面两个例子以点带面,浅提一下。
CC6的失效——LazyMap之殇
当Hessian反序列化Map
类型的对象的时候,会自动调用其put
方法,而put方法又会牵引出各种相关利用链打法。map.put对于HashMap会触发key.hashCode()。
利用到hashCode的链子有很多,如CC6和Rome相关链,上篇文章我们讲了Rome相关链的利用,但并没有介绍CC6的Hessian改链,并非不想,而是不可,现在我们来详细介绍下为何CC6不能配合Hessian反序列化来打
我们来跟进反序列化一个LazyMap的全过程
先是调用HessianInput#readObject
再switchcase进到77调用_serializerFactory.readMap
跟进_serializerFactory.readMap,getDeserializer去取LazyMap的deserializer
跟进,cl
是 Map 类或其子类,则创建一个 MapDeserializer
对象 作为deserializer
并使用传入的 cl
类型来初始化它
我们跟进MapDeserialzier的初始化方法,
发现根据传入的type(org.apache.commons.collections.map.LazyMap)取到的Constructor数组为空,进而走到最后的判断,使this._ctor为HashMap的Constructor(构造函数),问题也就在这里出现了!即是说LazyMap被当成HashMap来恢复了,自然也就打不了CC6
我主观推测,Hessian的MapDeserialzier怎么可能知道第三方库那些各种map的构造方法,而面对未知,最后都统一成jdk原生的HashMap的构造方法才更合理,也就是说第三方库里实现了Map接口的类应该都存在这个问题。
OK说回来,取到初始化后的MapDeserializer作为deserializer,再调用了readMap方法
我们跟进MapDeserializer#readMap
发现用HashMap的Constructor创建的map并非LazyMap,而是HashMap,到此破案。
Rome-TemplatesImpl链的失效——transient之殇
对于Rome,不出网的情况最简单粗暴应该是TemplatesImpl链,但在上文中我们却使用了SignedObject来打二次反序列化中转,显然,直接打TemplatesImpl链是有问题的。
问题何在?
因为TemplatesImpl类中被transient
修饰的_tfactory
属性无法被序列化,进而导致TemplatesImpl类无法初始化(TemplatesImpl那条链的defineTransletClasses要求_tfactory不为空,否则抛出异常)
可若是这样,transient是无差别的,那原生序列化不也一样无法写入_tfactory
属性吗?
莫急,我们注意到TemplatesImpl重写了原生readObject方法,在readObject中给_tfactory进行赋值,而Hessian中序列化和反序列化中都不会处理transient修饰的字段
病症也就在这了。
结语
Hessian不是原生反序列化,不能从传统反序列化角度带入思考