CVE-2020-2883——WebLogic反序列化初探

阅读量    133579 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

一、原理

(一)概述

和CVE-2015-4852中构造的ChainedTransformer类似,ReflectionExtractor可以实现任意方法调用,这里用链式的ReflectionExtractor构造ChainedExtractor,调用其extract()同样可以实现任意代码执行;

BadAttributeValueExpException中的readObject()可以调用成员变量的toString,且这个成员变量是我们可控的;

控制BAVEE的成员变量为LimitFilter对象,通过LimitFilter.toString()触发ChainedExtractor的extract(),进而触发RCE。

(二)CVE-2020-2883

CVE-2020-2555的补丁(仅)去除了LimitFilter.toString()中的extract()调用,

大概情况是这样,

当然,这条链断的并不完整,只要有一处能调用到我们构造的ChainedExtractor的extract(),则仍能触发ReflectionExtractor带来的任意方法调用。

(三)原理

1.工具分析

仍然是Y4er师傅的[PoC][https://github.com/Y4er/CVE-2020-2883/],

将其放到weblogic_cmd的com/supeream/下即可。

相关内容在下面结合调试过程一起讲。

记录一下感觉很奇怪的事情,

PoC运行到这里,

queue的显示是这样的,看不到成员变量,很烦,

但若是计算queue.comparator,

也是有值的,虽然跟一下就能发现这个问题,不影响调试,但看起来总有些不舒服。

仔细一想,发现了问题之所在,

不知哪一次为了看字节流方便,将View as 改了,改回Object之后,就恢复正常了。

2.原理

补丁虽然remove了LimitFilter.toString()中的extract,仍然有几个类可以调用到ChainedExtractor.extract()。比如MultiExtractor继承了AbstractExtractor ,其内的compare()就可以调用到ChainedExtractor.extract()。

另一方面,PriorityQueue也是反序列化常用的基类,通过readObject()->heapify()->siftDown()->siftDownUsingComparator(),进而触发this.comparator.compare()

 

二、调试

(一)环境搭建

同CVE-2020-2555,不再赘述。

(二)复现

运行PoC,

(三)调试

先上这个PoC的调用栈,

extract:104, ReflectionExtractor (com.tangosol.util.extractor)
extract:105, ChainedExtractor (com.tangosol.util.extractor)
compare:71, ExtractorComparator (com.tangosol.util.comparator)
siftDownUsingComparator:722, PriorityQueue (java.util)
siftDown:688, PriorityQueue (java.util)
heapify:737, PriorityQueue (java.util)
readObject:797, PriorityQueue (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1158, ObjectStreamClass (java.io)
readSerialData:2173, ObjectInputStream (java.io)
readOrdinaryObject:2064, ObjectInputStream (java.io)
readObject0:1568, ObjectInputStream (java.io)
readObject:428, ObjectInputStream (java.io)
readObject:73, InboundMsgAbbrev (weblogic.rjvm)
read:45, InboundMsgAbbrev (weblogic.rjvm)
readMsgAbbrevs:325, MsgAbbrevJVMConnection (weblogic.rjvm)
init:219, MsgAbbrevInputStream (weblogic.rjvm)
dispatch:557, MsgAbbrevJVMConnection (weblogic.rjvm)
dispatch:666, MuxableSocketT3 (weblogic.rjvm.t3)
dispatch:397, BaseAbstractMuxableSocket (weblogic.socket)
readReadySocketOnce:993, SocketMuxer (weblogic.socket)
readReadySocket:929, SocketMuxer (weblogic.socket)
process:599, NIOSocketMuxer (weblogic.socket)
processSockets:563, NIOSocketMuxer (weblogic.socket)
run:30, SocketReaderRequest (weblogic.socket)
execute:43, SocketReaderRequest (weblogic.socket)
execute:147, ExecuteThread (weblogic.kernel)
run:119, ExecuteThread (weblogic.kernel)

ChainedExtractor.extract()往上的部分就比较熟悉了,情况一致,不再赘述,重点关注从ChainedExtractor往下到PriorityQueue.readObject的片段,

接下来是从PriorityQueue.readObject()到PriorityQueue.siftDownUsingComparator()的部分,

1.this.queue

首先是queue的赋值,

会进入heapify(),

可以看出,在size>=2时,可以进入for的内部,进而进入siftDown函数,

这一部分在PoC中的体现如下,

PriorityQueue queue = new PriorityQueue(2, new ExtractorComparator(chainedExtractor1));
queue.add("1");
queue.add("1");
m_aExtractor.set(chainedExtractor1, valueExtractors);

Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = Runtime.class;
queueArray[1] = "1";

2.this.comparator

进入siftDown,我们看到,接下来的流程和comparator的值有关,跟踪之,

是个private,可以在构造函数中设定,

显然进入if,

跟进,因为size为2,前面的内容都可顺利走过,进入,此时x即为Runtime,c为1,

o1、o2对应x、c,

接下来即可进入this.m_extractor.extract,

先跟踪一下这个变量,

也是可以在构造函数里设定的,

对应着PoC中的如下部分,

Field m_aExtractor = clazz.getDeclaredField("m_aExtractor");
m_aExtractor.setAccessible(true);

m_aExtractor.set(chainedExtractor1, valueExtractors);

接下来进入extract(),这一部分和之前一模一样,不再赘述。

个人感觉CVE-2020-2883的整个利用链和CVE-2020-2555相比仍有一定的相似度,前者的利用链是套路A+ReflectionExtractor任意方法调用,后者是套路B+ReflectionExtractor任意方法调用。CVE-2020-2555的补丁破坏了套路B,但ReflectionExtractor的任意方法调用部分仍然是可用的,只要找到别的触发点,仍可以利用。

 

三、收获与启示

因为之前粗略学习过CVE-2020-14645,感觉CVE-2020-2883可谓是“政启开元,治宏贞观”,其利用链的一部分继承了CVE-2020-2555中ReflectionExtractor的利用链,另一部分找到了PriorityQueue可达的、新的extract()的调用点,为CVE-2020-14645做了准备。

学到现在,有一个直观的感受是:最开始的CVE-2015-4852是开篇,后面的都是它的再发展(包括它的重现、它的绕过和它的绕过的绕过),所谓发展主要是指反序列化触发点的切换。从最开始2015时CC1链及其变种,到现在出现了新的利用类ReflectionExtractor,又一次告诉我们要封一类,而不能只封一个。

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多