前不久,零队发了一篇《MySQL蜜罐获取攻击者微信ID》的文章,文章讲述了如何通过load data local infile进行攻击者微信ID的抓取,学习的过程中发现虽然问题是一个比较老的问题,但是扩展出来的很多知识都比较有意思,记录一下。
在MySQL中LOAD DATA INFILE 语句以非常高的速度从文本文件中读取行到表中,基本语法如下:
load data [low_priority] [local] infile 'file_name txt' [replace | ignore]
into table tbl_name
[fields
[terminated by't']
[OPTIONALLY] enclosed by '']
[escaped by'' ]]
[lines terminated by'n']
[ignore number lines]
[(col_name, )]
这个功能默认是关闭的,当我们没有开启这个功能时执行LOAD DATA INFILE报错如下:
> 1148 - The used command is not allowed with this MySQL version
我们可以通过如下命令查看功能状态。
show global variables like 'local_infile';
我们可以通过如下命令开启该功能。
set global local_infile=1;
开启之后我们就可以通过如下命令进行文件读取并且写入到表中,我们以C:1.txt为例,将其中内容写入到test表中,并且以n为分隔符。
load data local infile 'C:/1.txt' into table test fields terminated by 'n';
这样我们就可以读取客户端本地的文件,并写入到表中。
接下来我们通过Wireshark抓取过程中的流量分析一下通信过程。
首先是Greeting包,返回了服务端的Version等信息。
接下来客户端发送登录请求。
接下来客户端发送了如下请求:
SET NAMES utf8mb4SET NAMES utf8mb4
接下来我们执行我们的payload
load data local infile 'C:/1.txt' into table test fields terminated by 'n';
首先客户端发起请求;
之后服务端会回复一个Response TABULAR,其中包含请求文件名的包;
这里数据包我们要注意的地方如下:
如上图,数据包中内容如下:
09 00 00 01 fb 43 3a 2f 31 2e 74 78 74
这里的09指的是从fb开始十六进制的数据包中文件名的长度,00 00 01值得是数据包的序号,fb是包的类型,43 4a 2f 31 2e 74 78 74指的是文件名,接下来客户端向服务端发送文件内容的数据包。
在MySQL协议中,客户端本身不存储自身的请求,而是通过服务端的响应来执行操作,也就是说我们如果可以伪造Greeting包和伪造的文件名对应的数据包,我们就可以让攻击者的客户端给我们把我们想要的文件拿过来,过程大致如下,首先我们将Greeting包发送给要连接的客户端,这样如果客户端发送查询之后,我们返回一个Response TABULAR数据包,并且附上我们指定的文件,我们也就完成了整个任意文件读取的过程,接下来就是构造两个包的过程,首先是Greeting包,这里引用lightless师傅博客中的一个样例。
'x0a', # Protocol
'6.6.6-lightless_Mysql_Server' + '