0x00 前言

之前学习Jackson一条Gadget的时候涉及过,HW期间又发现类似的恶意利用工具和漏洞,就再补充一些细节。

0x01 MySQL客户端任意文件读取

LOAD DATA LOCAL INFILE

具体可参考:https://dev.mysql.com/doc/mysql-security-excerpt/5.7/en/load-data-local-security.html

MySQL支持使用LOAD DATA LOCAL INFILE语句,即可将客户端本地的文件中的数据insert到MySQL的某张表中。

注意,还有个LOAD DATA INFILE语句,这是加载服务端的文件而非客户端的。

LOAD DATA LOCAL INFILE的工作过程大致如下:

  1. 用户在客户端输入:load data local file “/data.txt” into table test;
  2. 客户端->服务端:我想把我本地的/data.txt文件插入到test表中;
  3. 服务端->客户端:把你本地的/data.txt文件发给我;
  4. 客户端->服务端:/data.txt文件的内容;

测试看下LOAD DATA LOCAL INFILE语句,用Kali作为客户端远程连接MySQL服务,然后执行如下SQL语句来将/etc/passwd文件中的内容插入到MySQL的users表中:

1
load data local infile "/etc/passwd" into table users FIELDS TERMINATED BY '\n';

漏洞原理

上述过程存在一个问题,即客户端发送哪个文件的内容,取决于第三步即服务端响应的想要的哪个文件,如果服务端是个恶意的MySQL,那么它可以读取客户端的任意文件内容,比如读取/etc/passwd:

  1. 用户在客户端输入:load data local file “/data.txt” into table test;
  2. 客户端->服务端:我想把我本地的/data.txt文件插入到test表中;
  3. 服务端->客户端:把你本地的/etc/passwd文件发给我;
  4. 客户端->服务端:/etc/passwd文件的内容;

而且,在大部分客户端(比如MySQL Connect/J)的实现里,第一步和第二部并非是必须的,客户端发送任意查询给服务端,服务端都可以返回文件发送的请求。而大部分客户端在建立连接之后,都会有一些查询服务器配置之类的查询,所以使用这些客户端,只要创建了到恶意MySQL服务器的连接,那么客户端所在的服务器上的所有文件都可能泄露。

注意:如果使用MySQL客户端直接连接的话,是需要添加--enable-local-infile选项的,而其他大部分MySQL客户端实现中,是默认开启的,比如allowLoadLocalInfile是MySQL的JDBC驱动的一个创建连接的配置项、用来控制是否允许从本地读取文件,默认值为True,具体的MySQL客户端实现得具体看。

漏洞复现

攻击流程如下:

  1. 攻击者开启伪造的恶意MySQL服务器,诱使受害者MySQL客户端访问;
  2. 受害者向恶意MySQL服务器发起请求,并尝试进行身份认证;
  3. 恶意MySQL服务器接受到受害者的连接请求后,发送正常的问候、身份验证正确并且发送LOAD DATA LOCAL INFILE语句来读取受害者客户端本地敏感文件;
  4. 受害者的MySQL客户端认为身份验证正确,执行攻击者的发来的请求,通过LOAD DATA LOCAL INFILE语句将本地文件内容发给恶意MySQL服务器;
  5. 恶意MySQL服务器接受到客户端敏感文件,Done;

GitHub上恶意MySQL服务相关项目:

开启恶意MySQL服务后,受害者尝试使用MySQL客户端连接恶意服务端(这里metasploitable机子的MySQL版本为5.0.51a-3ubuntu5,无需添加--enable-local-infile选项即可成功):

恶意MySQL服务端窃取到了/etc/passwd文件内容:

解决方案

针对LOAD DATA LOCAL INFILE的安全问题,MySQL官方给出如下说明:

为了避免连接到不受信任的服务器,客户端可以建立安全连接并通过使用--ssl-mode=VERIFY_IDENTITY选项和适当的CA证书进行连接来验证服务器身份 。

为避免出现LOAD DATA问题,客户应避免使用LOCAL

管理员和应用程序可以配置是否允许本地数据加载,如下所示:

  • 在服务器端:

    • 所述local_infile系统变量控制服务器端LOCAL 的能力。根据 local_infile设置,服务器会拒绝或允许请求本地数据加载的客户端加载本地数据。
    • 默认情况下,它local_infile 是禁用的。要显式地使服务器拒绝或允许LOAD DATA LOCAL语句(无论在构建时或运行时如何配置客户端程序和库),请在 禁用或启用的情况下启动mysqldlocal_infilelocal_infile也可以在运行时设置。
  • 在客户端:

或者:

1
2
3
>     [client]
> loose-local-infile=1
>
  • 在所有情况下,LOCAL 客户端成功使用加载操作还需要服务器允许本地加载。

如果LOCAL禁用了此功能,则在服务器或客户端上,尝试发出LOAD DATA LOCAL语句的客户端都会 收到以下错误消息:

1
2
> ERROR 1148: The used command is not allowed with this MySQL version
>

0x02 MySQL蜜罐

利用该漏洞可以制作MySQL蜜罐来诱使攻击者连接,从而窃取攻击者主机上的敏感信息。GitHub上已有可以读取攻击者微信ID的MySQL蜜罐,具体参见:https://github.com/qigpig/MysqlHoneypot