长亭百川云 - 文章详情

使用自定义ClassLoader解决反序列化serialVesionUID不一致问题

回忆飘如雪

69

2024-07-14

爱德华·马奈-沙滩上(1873年夏)

 0x01 

背景

**serialVesionUid不一致导致反序列化失败也算是Java反序列化漏洞利用比较常见的问题了。**查了下资料,发现了各种各样的方法,但没有找到一种适合所有gadget的通用解决方案,为此我花了一些时间,算是找到了自己心中比较完美的解决方案:自定义ClassLoader。目前已经将其集成到ysoserial中,可完美解决各类gadget serialVesionUID不一致问题。

 0x02 

各方案的优劣

在解决这个问题之前,我尝试的很多方法,简单说下它们各自能解决的问题和存在的缺陷。

方案1:修改序列化byte数据

该方法可解决序列化最终数据的serialVesionUID不一致,但无法解决Object的serialVesionUID不一致

方案2:反射修改serialVesionUID

可以解决1的缺陷,但无法解决Gadget依赖的class没有serialVesionUID属性的情况,因为反射只能修改Object的属性,不能添加。

方案3:修改Class字节码,添加或修改serialVesionUID

能解决Gadget直接依赖Class的serialVesionUID不一致问题,可弥补方案2的缺陷。但不好解决Gadget间接依赖class存在serialVesionUID不一致的情况。

方案4:ObjectStreamClass.getSerialVesionUID()

该方法负责返回所有参与序列化Class的serialVesionUID,Hook它并修改返回值,可解决所有class的serialVesionUID不一致问题。但它无法解决Gadget依赖jar版本之间,class差异较大,属性类型不同的情况。serialVesionUID发生改变的本质是因为Class的属性和方法发生了改变,如果属性类型改变了,单单只修改serialVesionUID是不够的。

方案5:URLClassLoader

使用URLClassLoader动态引入依赖jar可以很好的解决以上方案的缺陷。只是用在该场景下有些费劲,原因有三:

  • 第一,不方便隔离依赖。包含serialVesionUID不一致class的jar(这里简称不一致jar)是需要被隔离的,因为URLClassLoader是双亲委派模式,存在被父ClassLoader中的同名Class覆盖的风险。

  • 第二,不方便共享依赖。Gadget依赖的部分jar可能不存在serialVesionUID不一致问题(这里简称可共用jar),我们需要共享。

  • 第三,不方便添加Class到ClassLoader中,URLClassLoader只提供添加jar的方法。

 0x03 

自定义ClassLoader解决方案

在我看来比较完美的方案不仅要解决以上方案的缺陷,还要能防止各种未知的"副作用"。使用ClassLoader来解决的思路肯定是没错,但我们需要结合解决serialVesionUID不一致问题这个场景量身设计一个ClassLoader,核心有两点:

1. 改双亲委派为当前ClassLoader优先,方便隔离不一致jar共享可共用jar

2. 方便添加Class和Jar到ClassLoader中

那么自定义ClassLoader是如何解决serialVesionUID不一致问题的呢?

自定义ClassLoader可以很方便地切换不一致jar为漏洞环境的对应版本,生成的发序列化数据自然不会存在serialVesionUID不一致问题。

具体实现如下图,我们自定义ClassLoader包含了Gadget class和不一致jar。当Gadget class实例化生成序列化对象时,由于当前ClassLoader优先原则,存在不一致问题的class使用的是自定义ClassLoader加载的,实现隔离。而其他Class找不到,自然走双亲委派模式,去父ClassLoader中查找,实现共享。

下面我们分别来实现。

 0x04 

addClass && addJar

首先我们自定义的ClassLoader需要维护要一个装载Class的Map classByteMap,类名为键,类文件byte数据为值。方便后续添加和获取Class。

addClass方法,主要是为了方便我们我们把Gadget对应的class添加的自定义ClassLoader中。

addJar方法,主要是为了方便把gadget的不一致jar快速添加到ClassLoader中。具体来说就是读取不一致jar中所有class的class name和class byte,存储到classByteMap中。

 0x05 

改双亲委派为自定义ClassLoader优先

要想打破双亲委派,我们需要重新loadClass方法,修改加载逻辑为优先使用自定义ClassLoader加载。

findClass方法定义的是自定义ClassLoader查找Class的逻辑

 0x06 

编写版本兼容gadget

依然以ysoserial CommonsBeanutils1为例子。ysoserial中默认commons-beanutils是1.9.2版本,下面我们给它添加一个兼容1.8.3版本的CommonsBeanutils1_183。

通过对比1.9.2和1.8.3序列化数据,发现serialVesionUID不一致的只有org.apache.commons.beanutils.BeanComparator类,它在commons-beanutils-.jar中,剩余的commons-collections-3.1.jar和commons-logging-1.2.jar为可共用jar。

接着就可以编写代码,调用自定义ClassLoader SuidClassLoader来解决serialVesionUID不一致问题了。

Weblogic coherence.jar的gadget可如法炮制。近期忙完会将完整的代码上传到github项目

http://github.com/woodpecker-framework/ysoserial-woodpecker

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2