0x00 前言

本文还是采取简略概述的模式。

0x01 思路

matthias_kaiser前辈给出的链子:

/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()

by @matthias_kaiser

*/

接下来我们就按照这条链子以及寻找的思路进行分析。

0x02 cc6

lazyMap.get()

链子尾部与cc1国外链几乎一致,我们直接写出poc:

image-20241204104936981

现在希望找到调用get方法的地方。

TiedMapEntry

TiedMapEntry.getValue()

查找用法会发现get方法被调用的太多,这里直接给出调用方法:TiedMapEntry.getValue()

image-20241204110155871

跟进,查看方法实现和类签名:

image-20241204110338719

map和key是TiedMapEntry类的成员参数,所以必须查看TiedMapEntry类的构造方法:

image-20241204110559364

现在尝试以TiedMapEntry类为头部构造poc:

image-20241204110848932

poc可行,寻找调用getValue方法的地方。

TiedMapEntry.hashCode()

寻找调用方法,不妨先在本类寻找一下。TiedMapEntry类里hashCode方法调用了getValue方法:

image-20241204111533529

hashCode方法可是非常好的方法,每一个类都有该方法。

目前的poc只需要改上面poc的最后一行就可以,接着往下看。

初步希望存在一个类:在调用readObject方法时就会调用成员参数的hashCode方法。

HashMap

初步

想到hashCode方法,再回忆一下URLDNS链:

HashMap被反序列化后在一定条件下会调用参数key的hashCode方法,我们选择URL类对象作为这个key

如果这个key是TiedMapEntry类实例,那么在readObject方法里就会执行TiedMapEntry.hashCode方法,进而成功执行危险方法。

调用逻辑如下:

HashMap.readObject() -> putVal(hash(key), key, value, false, false) -> hash(key) -> key.hashCode()

关键是成员参数key,先尝试poc:

image-20241204114426092

poc弹出了计算器,成功了吗?

在序列化一行打个断点,发现序列化之前就弹出了计算器,再测试一下ser.bin反序列化能不能弹出计算器:不行。

看来我们忽略了一些地方。

弹计算器还有一个原因,只需关闭下图所指选项即可:

image-20241204182544090

检查

调试深入:

image-20241204183221994

在HashMap.put时LazyMap.key已经赋值了:

image-20241204183159056

反序列化时若key值存在,就不会进行下一步的调用。这里的key是构造LazyMap实例的参数key。

如果直接在put后移除这个key,其实就可以成功进行反序列化了,poc如下:

image-20241204191102345

image-20241204191201161

但是细心的读者会发现,这种方法在序列化之前还是会弹出calc,虽然没什么影响。

有兴趣的读者可以往下看怎么解决这个问题:

可以想到,put是一定会成功调用一次链子,所以我们希望put调用的是没有作用的链子;等到put执行后通过反射再改为有作用的链子——其可以被readObject成功调用。给出poc:

image-20241204192127055

细心的读者还是不难发现,这里并不只可以修改ChainedTransformer类,只要是这条调用链上的都可以修改,比如组长对LazyMap类进行修改,不妨一试,给出poc:

image-20241204192916233

有兴趣的不妨试试TiedMapEntry类,这里就不再测试了。

至此,cc6就搞定了。

0x03 结语

cc6如果只是学习,难度其实还好。但是学习的目的之一是掌握一般性的技能方法,所以重点应该放在如何找,如何调试上面。