Java反序列化Commons-Collections篇04-CC3链

0x00 前言

组长讲得还是那么好,但是这条链有点长,其中的知识有点多,所以我写得会多一点。

cc3的优点在于没有用到InvokeTransform类,相当于多了一种攻击手段。

0x01 思路

  • 代码执行方式

从某种程度上说,Java反序列化的目的是实现任意代码执行。

但是开发者往往不会在程序里留下常见的危险方法,这就需要我们动态调用危险方法,比如通过Java反射机制或者静态代码块执行/构造函数执行

在前面所学的cc1、cc6等链子中,我们采用的是Java反射机制(主要是InvokeTransform类),本文所学的cc3链将采用静态代码块执行(构造函数执行也是一样的),并运用到cc1、cc6等链子中。

  • 类初始化

静态代码块执行的条件是所在类进行初始化,也就是newInstance。想要执行一个类的静态代码块,就需要想办法加载这个类并且初始化。

所以寻找底部链子的思路就是:

找到可以执行任意类加载并且将其初始化的方法,然后调用上述方法。

当底部链子找到以后,再一层层往上找,直至找到readObject方法。

0x02 cc3

底部链子

类加载 -> 类初始化 -> 静态代码块调用

ClassLoader.defineClass()

静态代码块所在类是用户自定义的类,我们的目的是加载这个类

跟类加载相关的类是ClassLoader类,该类进行类加载的核心方法是loadClass方法。loadClass方法先按照双亲委派机制向父类加载器请求加载目标类;如果父类加载器无法加载目标类,则使用findClass方法,而findClass方法又会调用defineClass方法。defineClass方法的作用是将字节码定义为一个Class对象,符合我们的目的。

但是defineClass方法被重写了很多种:

image-20241207170322815

查找用法,希望找到一个类可以调用defineClass方法:(这里直接给出)

image-20241207170507672

TemplatesImpl.TransletClassLoader.defineClass()

跟进该方法:

image-20241207170743467

该方法是default类型,查找用法:

image-20241207170846295

父类的defineTransletClasses方法是private类型,再查找用法:

image-20241207171035968

前两个方法只是单纯的类加载,并没有初始化;第三个方法则进行了初始化:

image-20241207172350274

该方法是私有的,查找调用:

image-20241207183650242

终于遇到public类型的方法了!先尝试写个poc:

image-20241207190748644

这里不妨思考一下_name_bytecodes_tfactory这三个属性的作用,或者说为什么要反射修改它们。

_tfactory属性不用修改也可以反序列化弹calc,这里是为了更好地展示poc,无伤大雅。

至此,我们的链子尾部TemplatesImpl类搞定了,下一步是一步步往上调用直至readObject方法

但是在下一步之前,想必读者并不能成功弹calc,且看下文:

静态代码块

image-20241207193449270

箭头所指的地方自然有其用处,如果不继承AbstractTranslet类,程序会报空指针错误,具体的细节如下:

image-20241207193706979

这里最好跟着组长调试,直接给出问题:

image-20241207193959377

满足第一个箭头所指的if条件即可,上文已经给出答案了。

往上调用

其实到了这一步已经可以采用反射了,可以通过cc1的InvokeTransform类甚至往上的整条链来构造cc3链。

但是我们的目的就是不想使用InvokeTransform类,这里就不赘叙上述简单的拼接了。

TrAXFilter

上文所讲的TemplatesImpl.newTransformer方法可以被其他类调用,那就查找用法:

image-20241207195347057

锁定TrAXFilter类,调用如下:

image-20241207195631354

这个类不能序列化,那么这个链节点就不能被序列化保存,进而无法进行反序列化。但是有这么一个类及其方法,可以接受参数并调用该参数的构造方法。

细品,序列化保存的数据是静态的数据,但若把那些不可序列化的数据以动态的形式调用,照样可以保持链子不崩坏。

这个类就是InstantiateTransformer类。既然学到这里了,给出一个类想必读者可以自行写出当前的poc:

image-20241207201010185

都transform方法了,下一步的poc直接用cc1的(cc6的也可以),完整的poc给出:

image-20241207202533920

0x04 结语

想必读者已经深有感悟,Java反序列化的链子各个部分还是比较独立的(起码在cc链是这样的)。