Mysql服务端反向读取客户端的任意文件
1 原理
Mysql服务端反向读取客户端的任意文件
利用LOAD DATA INFILE
这个语法,这个语法主要用于读取一个文件的内容并且放到一个表中。
load data infile "/data/data.csv" into table TestTable;
load data local infile "/home/lightless/data.csv" into table TestTable;
第一行是读取服务端本地的文件,第二行是读取客户端本地的文件
而反向读取就是利用了第二行用法。
正常流程:
- s1 客户端:hi~ 我将把我的 data.csv 文件给你插入到 test 表中!
- s2 服务端:OK,读取你本地 data.csv 文件并发给我!
- s3 客户端:这是文件内容:balabal!
当s2时,服务端返回给客户端的不是data.csv,而是其他文件时,就会发生如下事情
- s1 客户端:hi~ 我将把我的 data.csv 文件给你插入到 test 表中!
- s2 服务端:OK,读取你本地的 / etc/passwd 文件并发给我!
- s3 客户端:这是文件内容:balabal(/etc/passwd 文件的内容)!
为什么会这样?
Mysql官方文档:
“In theory, a patched server could be built that would tell the client program to transfer a file of the server’s choosing rather than the file named by the client in the LOAD DATA statement.”
客户端读取哪个文件其实不是自己说了算,是服务端说了算,也就是以s2时服务端返回的文件目标为准!
到了这里有个问题,如果客户端不主动使用LOAD DATA INFILE,是不是就没事了呢?
还是官方文档:
"A patched server could in fact reply with a file-transfer request to any statement, not just LOAD DATA LOCAL"
意思就是,伪造的服务端可以在任何时候回复一个 file-transfer 请求,不一定非要是在LOAD DATA LOCAL的时候。
一些Mysql客户端,比如python的MySQLdb和mysqlclient,php的mysqli和PDO,java的JDBC Driver以及原生mysql客户端等等,在连接MySQL的时候,基本上在连接成功之后都会发出一些SELECT语句来查询一些版本号、编码之类的数据,这时就可以回复一个 file-transfer 请求,读取客户端上的文件。
这里有一点要说明的是,如果想要利用此特性,客户端必须具有 CLIENT_LOCAL_FILES
属性,所以可能要添加--enable-local-infile
。
总结一下漏洞的成因:
LOAD DATA INFILE
读哪个文件是由服务端返回包的file-transfer 请求决定,而不是客户端- 不管客户端发出什么请求,只要服务端回复一个 file-transfer 请求,客户端就会按照
LOAD DATA INFILE
的流程读取文件内容发给服务端
总结一下整个攻击流程:
- 受害者向攻击者提供的服务器发起请求,并尝试进行身份认证
- 攻击者的MySQL接受到受害者的连接请求,攻击者发送正常的问候、身份验证正确,并且向受害者的MySQL客户端请求文件。
- 受害者的MySQL客户端认为身份验证正确,执行攻击者的发来的请求,通过LOAD DATA INLINE 功能将文件内容发送回攻击者的MySQL服务器。
- 攻击者收到受害者服务器上的信息,读取文件成功,攻击完成。
做个补充:
甚至不需要真的搞个Mysql服务,在mysql客户端连接时,模仿服务端返回Server Greeting
等待 Client 端发送一个Query Package后
回复一个file transfer请求
即可读取到文件
复现用的脚本既是这样实现
2 条件
- 受害者的Mysql客户端有权限读文件
- 受害者的Mysql客户端设置中,
local_infile
非0或连接时有用--enable-local-infile
,默认是能够读取的
3 利用场景
- 利用重装漏洞,读取目标服务器上的任意文件
- 利用目标的数据迁移等,能连接外部数据库的功能点,读取目标服务器上的任意文件
- 搭建在蜜罐上读取攻击者的信息,蓝队溯源/反制
4 复现
大佬写好的脚本
https://github.com/allyshka/Rogue-MySql-Server
roguemysqlserver.py
的filelist
为读取受害者的文件地址,读Win注意路径
python2运行roguemysqlserver.py
,服务器开放端口和防火墙即可
4.1 mysql原生client
ubuntu18/Win10
-
服务端运行
roguemysqlserver.py
-
客户端连接
其实无需密码即可连接上,即mysql -h
即可连接上
-
读取文件
4.2 navicat premium12
ubuntu18/Win10
-
客户端
-
读取文件
4.3 公网测试
尝试读取多个文件时,发现原脚本所读文件不存在时,并不是继续读下一个文件,而是停了下来。。。。
能力有限,不会修改,希望有大佬赐教
一晚上只有几台机器连上来,还读不到文件就很难受
几天了,很多IP连进来,但是没一个读到的,有一上海的IP,好像不信邪,试了好几次。。。
4.4 其他大佬写的利用工具
https://github.com/fnmsd/MySQL_Fake_Server
https://github.com/rmb122/rogue_mysql_server
5 防御/修复
- 使用
--ssl-mode=VERIFY_IDENTITY
来建立可信的连接 - 从配置上防御
https://dev.mysql.com/doc/refman/8.0/en/load-data-local-security.html
6 参考
https://lightless.me/archives/read-mysql-client-file.html
https://xz.aliyun.com/t/3973