长亭百川云 - 文章详情

WebLogic 反序列化CVE连环三连击

闻道解惑

94

2024-07-13

Java 反序列化漏洞的利用有两个条件。首先是漏洞点,也就是将攻击者可控的内容传递给 ObjectInputStream.readObject() 函数的调用链;另一个条件是gadget,也就是从某个类的反序列化入口函数 readObject() 开始,一步步执行到危险函数的调用链。

WebLogic 对于 T3 协议和 IIOP 协议的处理,天然就会进行反序列化的漏洞点。因此,对于 WebLogic 反序列化漏洞的挖掘,主要就是在 gadget 的寻找和补丁绕过上。

2020年的1月、4月和7月, WebLogic 先后爆出了三个一脉相承的反序列化 CVE,涉及了七个 gadget。下面简单分析一下这三个 CVE 以及相关的 gadget

CVE-2020-2555

2020年1月,CVE-2020-2555 被公开。这个反序列化 gadget 有三条利用链。

三条利用链都利用了 JDK 中的 BadAttributeValueExpException。这个类的特点是可以将对 readObject() 的调用,转换成对 toString() 函数的调用。

BadAttributeValueExpException 的这个特性,可以显著扩大反序列化 gadget 的范围,因此反序列化利用工具 ysoserial 中,有五条利用链都使用这个类作为入口。

经过从 readObject() 到 toString() 的转换之后,找到真正的入口函数:LimitFilter.toString()

函数中调用的两处 extracotor.extract() 函数来自接口 ValueExtractor.

搜索一下这个接口函数的实现,共29个。

CVE-2020-2555 的第一个调用链,利用了 ChainedExtractor 和 ReflectionExtractor 的两个 extract() 函数实现。

这两个实现可以完美的串起一条利用链,和 ysoserial 里 CommonsCollections1 利用链中所使用的 ChainedTransformer.transform() 和 InvokerTransformer.transform() 几乎一模一样。

由此我们可以构造出 POC,基本原则是:

  • 1、使用 BadAttributeValueExpException 作为反序列化的入口类,从而调用到 toString()

  • 2、使用 LimitFilter 对象作为前者的 valObj,从而调用到 extract()

  • 3、使用 ChainedExtractor 作为 LimitFilter 的 m_comparator,从而可以进行链式 extract()

  • 4、使用 ReflectionExtract 构建 ChainedExtractor,从而可以链式调用 method.invoke() 从而成功调用 Runtime.getRuntime().exec()

最终的调用栈如下:

CVE-2020-2555 的第二条利用链,同样来自上面 29 个 ValueExtractor.extract() 的实现类之一:MvelExtractor

熟悉 MVEL 的你应该一眼就看出了利用方法,只要使用 MvelExtractor 替换掉前一个利用链的 34两步就可以了。最终调用栈如下:

第三条利用链,同样来自上面 29 个实现类之一:MultiExtractor

由于 MultiExtractor.extract() 函数中没有链式调用,因此我们可以将 MultiExtractor 作为连接第一条利用链中 LimitFilter.toString() 和 ChainedExtractor.extract() 的桥梁。LimitFilter.toString() 间接通过 MultiExtractor.extract() 调用到 ChainedExtractor.extract() 中。最终的调用栈如下:

至于修复补丁,Oracle 打在了 LimitFilter.toString() 函数里。这个修复很神奇,仅仅封锁了三条调用链的入口,而从 MultiExtractor.extract() 经过 ChainedExtractor.extract() 调用到 ReflectionExtractor.extract() 的利用链、以及MvelExtractor.extract() 的利用链依然存在,只要再找一个入口就好了。

CVE-2020-2883

2020 年 4 月,CVE-2020-2883 被公开。同样使用了上述三条利用链,只是更换了入口函数。

前面说到,入口函数 LimitFilter.toString() 被修补,我们需要寻找一个新的入口。这个新入口同样可以在反序列化的时候,调用到 ValueExtract.extract() 中。

很快,大神们就找到了:ExtractorCompartor.compare()

ExtractorComparator.compare() 其实是对 jdk 中 Comparator.compare() 这个接口函数的实现。

那么,怎么从 readObject() 调用到 Comparator.compare() 函数呢? ysoserial 早就给出了答案:PriorityQueue

调用链如下:

PriorityQueue.readObject()    -> PriorityQueue.heapify()        -> PriorityQueue.siftDown()            -> PriorityQueue.siftDownUsingComparator()                -> Comparator.compare()

现在,我们将 CVE-2020-2555 的三条利用链稍加改造,就能实现 CVE-2020-2883 三条新的利用链:

  • 1、使用 PriorityQueue 代替 BadAttributeValueExpException 作为反序列化的入口类,从而通过 readObject() 调用到 compare()

  • 2、将 ExtractorComparator 对象设置为 PriorityQueue 的 comparator 属性值,从而通过 compare() 调用到 extract()

  • 3、将 ChaninedExtractor 或 MvelExtractor 或 MultiExtractor 设置为 PriorityQueue 的队列元素,从而通过 extract() 调用到目标函数 method.invoke() 或 MVEL.excuteExpression()

这样就能顺利绕过 CVE-2020-2555 的补丁修复,构成了三条换汤不换药的新利用链。

以第一条利用链为例,调整后的最终调用栈如下。

至于修复补丁,Oracle 并没有封禁利用链条上的 PriorityQueue 和 ExtractComparator ,只是将 ReflectionExtractor 和 MvelExtractor 放到了反序列化黑名单中。

仔细看下 CVE-2020-2883 的几个调用栈,从 PriorityQueue.readObject() 到 ExtractorComparator.compare() 再到 ValueExtractor.extract() 的利用链仍然存在,所以只需要在 29 个实现类中再找一个新的利用类就可以完成不定的绕过。

CVE-2020-14645

腾讯蓝军很快就找到了新的可利用的实现类 UniversalExtractor。这也是2020年7月公开的 CVE-2020-14645。

只是这里在调用 method.invoke() 时存在限制条件,函数名称必须是 get或 is 起始。因此可以利用那些已知的 Json 反序列化 gadget 链进行攻击。一个简单示例的最终调用栈如下:

心得

通常寻找反序列化 gadget,不论是用工具搜索还是手工进行,我们会将 readObject() 作为 source,将那些危险函数(如method.invoke()Runtime.exec()FileOutputStream.write()等)作为 sink进行查找。但其实,在 Java 纷繁复杂的各种依赖库中,已经存在了许许多多的代码链片段可以利用。例如 BadAttributeValueExpException 将 toString() 纳入了利用链,PriorityQueue 将 compare() 纳入了利用链,ExtractorComparator 将 extract() 纳入了利用链,等等等等。在搜索的时候,将这些扩展出的利用链作为 source 或 sink,会大大增加搜索的范围,也很可能会发现新的世界。

另一方面,对于漏洞的修复者而言,并不是堵住了入口就算修复了漏洞,而是要全方位封锁调用链上的方方面面,否则就会向 Oracle 一样留下永远补不完的 CVE

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备2024055124号-2