实验--Mysql服务端反向读取客户端的任意文件
摘要
伪造MySQL服务器对客户端实现任意文件读取
### 实验--Mysql服务端反向读取客户端的任意文件
实验环境:
客户端:kali-linux-2020.3 | MySQL:10.5.12-MariaDB-1
服务端:centos8 | MySQL:5.6.50-log
综合参考:https://lightless.me/archives/read-mysql-client-file.html
环境准备-kali上安装mysql
1.安装包
1 | apt-get install mariadb-client |
2.文件配置
/etc/mysql/my.cnf
添加:
1 | [client-server] |
3.启动与初始化
1 | service mysql start #启动myslq |
原理准备
-Load Data infile
LOAD DATA INFILE 语句以非常高的速度从文本文件中读取行到表中,可用来快速导入数据
该语法通常有两种用法,分别是:
1 | load data infile "/data/data.csv" into table TestTable; |
有时候也会与
FIELDS TERMINATED BY '\n'
一起使用,效果更佳。这两种用法的区别就是差了一个local
,第一个 SQL 语句的意思是,读取服务器上/data/data.csv
文件,并写入到TestTable
中;第二个 SQL 语句的意思则是,读取本地(客户端)这边的/home/lightless/data.csv
文件,并写入到TestTable
中。而我们这次要利用的也就是LOAD DATA LOCAL INFILE
这种形式。
load data local infile
就是客户端申请将本地文件写入表中的语句,我们可以从这个语句切入,看看这个机制是如何运作的
-抓包分析
参考:
– 抓包分析参考
握手认证阶段
wireshark 过滤设置port:3036
kali远程连接服务器上的mysql:
1 | mysql -h xxxx -u test -p |
这十三条响应就是客户端与服务端建立连接的过程
可以看到在握手认证阶段:
- greeting 握手初始化包
- login 登陆认证消息
- Response OK 认证结果
- 初始化查询语句等
Statement: select @@version_comment limit 1
……
认证成功则会进入命令执行阶段;
命令执行阶段
现在在客户机上执行:
1 | LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY '\n'; |
- query语句发送,申请上传文件
- 服务器返回一个文件传输申请(file-transfer请求)(TABULAR)
- 客户端发送
Malformed Packet
包,包含上传的数据文件
这看起来十分合理!
-不安全的file-transfer
参考:https://www.cnblogs.com/Rain99-/p/13334755.html#41-mysql%E5%8E%9F%E7%94%9Fclient
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.”
二:
“A patched server could in fact reply with a file-transfer request to any statement, not just LOAD DATA LOCAL”
无论你是否使用LOAD DATA LOCAL,服务端都可以回复一个 file-transfer 请求,客户端接到此请求,就会返回一个指定的文件内容。
于是,我们依照此思路,伪造一个MySQL服务器,伪造发包即可。
伪造MySQL服务器
攻击条件
如果想要利用此特性,客户端必须具有 CLIENT_LOCAL_FILES
属性,所以请求连接时可能要添加--enable-local-infile
以打开功能。现实情况中,某些功能的开启可能需要此属性。
攻击流程
- 受害者向攻击者提供的服务器发起请求,并尝试进行身份认证。
- 攻击者的MySQL接受到受害者的连接请求,攻击者发送正常的问候、身份验证正确,成功连接后向受害者的MySQL客户端请求文件。
- 受害者的MySQL客户端认为身份验证正确,执行攻击者的发来的请求,通过
LOAD DATA INLINE
功能将文件内容发送回攻击者的MySQL服务器。- 攻击者收到受害者服务器上的信息,读取文件成功,攻击完成。
服务端伪造
参考:
-包伪造:
不需要真的搞个Mysql服务,在mysql客户端连接时,模仿服务端返回Server Greeting
等待 Client 端发送一个Query Package后
回复一个file transfer请求
即可读取到文件大概就像……:
客户端:hi,现在我要查询一下版本信息
服务端:好的,把/etc/passwd文件发过来吧
客户端:好的,这是我的/etc/passwd文件
我们用python模拟这一过程,不用去考虑其他层次的协议,python帮助我们完成了这个工作,只需要关注MySQL Protocol
greeting package:
auth :认证消息包
file-transfer :文件传输请求
格式:https://dev.mysql.com/doc/internals/en/com-query-response.html
1 | 0c 00 00 01 fb 2f 65 74 63 2f 70 61 73 73 77 64 ...../etc/passwd |
前面的0x0c
是数据包的长度(从 \ xfb 开始计算),长度后面的三个字节\x00\x00\x01
是数据包的序号。
即:数据包长度
+数据包序号
+数据包内容
;
我们需要等待一个来自 Client 的查询请求,才能回复这个读文件的请求
那么,如何做呢?
-PoC
参考:*PoC参考*
1 | # coding=utf-8 |
攻击测试
服务器在 6666
开启服务
客户机:mysql -h ip:xxxxx -P 6666 --enable-local-infile
效果拔群🤣!
其他PoC
大佬脚本:https://github.com/allyshka/Rogue-MySql-Server
脚本运行后,会在当前目录下生成mysql.log目录,有客户端连接上后,进行记录,并且将文件读取存入,我们打开mysql.log文件,可以看到成功读取。
学习
学习大佬的总结😂:
对于这种攻击的防御,说起来比较简单,首先一点就是客户端要避免使用 LOCAL 来读取本地文件。但是这样并不能避免连接到恶意的服务器上,如果想规避这种情况,可以使用
--ssl-mode=VERIFY_IDENTITY
来建立可信的连接。当然最靠谱的方式还是要从配置文件上根治,关于配置上的防御问题,可以参考这篇文档进行设置。
用途的话,做蜜罐是肯定可以的,但是受众面好像不太完整,各种语言的支持都不太一样,比如 Python 中的 MySQLdb 包,原作者说这个包不受影响,但是我测试的时候确是受影响的,而 PHP+PDO 的方式又不受影响,所以能否中招还是要靠一些运气。
而且这些语言中的三方包在连接
MySQL
的时候,基本上在连接成功之后都会发出一下SELECT
语句来查询一些版本号、编码之类的数据,这就达成了前面提到过的第二个攻击条件:等待客户端发来一个QUERY
请求,所以如果这些第三方包允许执行LOAD DATA INFILE
,危害还是比较大的。
参考文章:
Mysql服务端反向读取客户端的任意文件
实验--Mysql服务端反向读取客户端的任意文件