黑客
登录
客服
网络安全
网络安全,渗透测试

从Weblogic原理上探究CVE-2015-4852、CVE-2016-0638、CVE-2016-3510究竟怎么一回事

围观人数:2970 日期:2020/11/2 10:40:36

​ 目前。网上关于CVE-2015-4852漏洞的资料很多,但是针对CVE-2015-4852漏洞如何修复,修复补丁又是如何生效的却少之又少;而CVE-2016-0638、CVE-2016-3510这两个漏洞又是如何绕过CVE-2015-4852补丁的,通常只是在介绍Weblogic系列漏洞时被一句话带过。

​ CVE-2015-4852、CVE-2016-0638以及CVE-2016-3510,这三个漏洞有着极其相似的地方,其本质就是利用了Weblogic反序列化机制,而官方在修复CVE-2015-4852时,也并未对这个机制进行调整,而仅仅是在此基础上增加了一个关卡:黑名单。

​ 因此,在彻底搞清楚Weblogic反序列化漏洞的原理以及如何修复这个问题之前,很有必要弄清楚Weblogic处理流量中的java反序列化数据的流程。只有清楚了这一点,才能很好的理解如下几个问题:

  1. CVE-2015-4852是如何产生的以及后续是如何修复的?

  2. 修复CVE-2015-4852,为何要在resolveClass:108,InboundMsgAbbrev\$ServerChannelInputStream (weblogic.rjvm)处添加黑名单?

  3. CVE-2016-0638、CVE-2016-3510是如何绕过修复?二者的绕过方式有何相同与不同?

Weblogic 反序列化攻击时序

​ 为了搞清楚CVE-2015-4852、CVE-2016-0638、CVE-2016-3510中的种种疑团,我们需要首先来弄明白一些原理性的东西,我们先从Weblogic
反序列化攻击时序入手,看看Weblogic是如何从流量中将序列化字节码进行反序列化。

​ 首先贴出一张Weblogic 反序列化攻击时序图

​ 这张图是从我的好朋友廖新喜大佬博客扒下来的,也欢迎大家去读一读他的关于java漏洞的分析文章:

http://xxlegend.com/2018/06/20/%E5%85%88%E7%9F%A5%E8%AE%AE%E9%A2%98%20Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AE%9E%E6%88%98%20%E8%A7%A3%E8%AF%BB/

​ 上图为一张完整的Weblogic反序列化攻击时序图,庞大而且繁杂,不如我们将其拆分开,首先说说Weblogic如何从流量数据取出序列化数据并获取其类对象的过程。

从流量数据到Class对象

​ 首先我们来看一张图:

​ Weblogic通过7001端口,获取到流量中T3协议的java反序列化数据。从上图中readObject开始,经过流程中的一步步的加工,并最终于上图流程终点处的resolveProxyClass或resolveClass处将流量中的代理类/类类型的字节流转变为了对应的Class对象。

​ 首先我们可以发现:在ObjectInputStream (java.io)中的readClassDesc方法处,存在着分叉点,导致了序列化流量流向了两个不同的分支:其中一些流量流向了readProxyDesc并最终采用resolveProxyClass获取类对象,而另一些则流向了readNonProxyDesc并最终使用resolveClass获取类对象。

readClassDesc是什么?

​ 从上文来看,流量数据经过readClassDesc并驶入了不同的处理分支。

​ 首先来看一下readClassDesc方法的官方注释:“readClassDesc方法读入并返回(可能为null)类描述符。将passHandle设置为类描述符的已分配句柄。”

​ 如果想理解官方注释的含义,需要扩充一些java序列化的知识:

​ java序列化数据在流量传输,并不是随随便便杂乱无章的,序列化数据的格式是要遵循序列化流协议。

序列化流协议定义了字节流中传输的对象的基本结构。该协议定义了对象的每个属性:其类,其字段以及写入的数据,以及以后由类特定的方法读取的数据。

字节流中对象的表示可以用一定的语法格式来描述。对于空对象,新对象,类,数组,字符串和对流中已有对象的反向引用,都有特殊的表示形式。比如说在字节流中传递的序列化数据中,字符串有字符串类型的特定格式、对象有对象类型的特定格式、类结构有着类结构。而TC_STRING、TC_OBJECT、TC_CLASSDESC则是他们的描述符,他们标识了接下来这段字节流中的数据是什么类型格式的

​ 以TC_CLASSDESC为例,TC_CLASSDESC在流量中的值是(byte)0x72,在序列化流协议中,当这个值出现后,代表接下来的数据将开始一段Class的描述(DESC=description),即TC_CLASSDESC描述符(byte)0x72后面的字节流数据为Class类型。通过这些描述符,程序可以正确的解析流量中的序列化数据。

​ 如果对这部分感兴趣,可以参照oracle文档:

https://www.oracle.com/security-alerts/cpuoct2020traditional.html

​ readClassDesc的功能很简单:读入字节流,通过读取字节流中的描述符来确定字节流中传递数据的类型,并交给对应的方法进行处理。

​ 接下来我们看看readClassDesc的实现

private ObjectStreamClass readClassDesc(boolean unshared) 
    throws IOException 
    {
    byte tc = bin.peekByte();
    switch (tc) {
        case TC_NULL:
        return (ObjectStreamClass) readNull();

        case TC_REFERENCE:
        return (ObjectStreamClass) readHandle(unshared);

        case TC_PROXYCLASSDESC:
        return readProxyDesc(unshared);

        case TC_CLASSDESC:
        return readNonProxyDesc(unshared);

        default:
        throw new StreamCorruptedException(
            String.format("invalid type code: %02X", tc));
    }
    }

最新文章

推荐文章

热门文章

黑客技术 黑客软件 黑客教程 黑客书籍

关于我们 | 免责声明 | 学员守则 | 广告服务 | 联系我们

©2013-2020 xf1433.com 版权所有

本站资源仅供用于学习和交流,请遵循相关法律法规