伪造mysql服务器,任意读取文件

使用场景

在一些cms的install页面下要提供mysql服务器
利用伪造mysql服务器,就可以任意读取cms的服务器下的文件
或者蜜罐

复现过程

先利用如下脚本与正常的mysql服务器进行交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$mysqli = new mysqli("127.0.0.1", "root", "123456", "mysql", 3306);
if (!$mysqli) {
echo "Error: Unable to connect to MySQL." . PHP_EOL;
echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL;
echo "Debugging error: " . mysqli_connect_error() . PHP_EOL;
exit;
}
if ($result = $mysqli->query("SELECT * FROM user")) {
printf("Select returned %d rows.\n", $result->num_rows);
$result->close();
}
echo "Success: A proper connection to MySQL was made! The mysql database is great." . PHP_EOL;
echo "Host information: " . mysqli_get_host_info($mysqli) . PHP_EOL;
mysqli_close($mysqli);

利用wireshark抓包,注意如果发现MySQL包只有两个其他都是SSL数据,
需在配置文件的[mysql]节添加skip_ssl
wireshark抓包结果
1.greeting包

2.登入请求包

3.请求执行select * from user

4.执行select * from user后返回的包(内容太多只截了一部分)

5.退出mysql

那么接下来将sql语句替换成
LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY '\n'
注意这里的test表要存在,不然mysql先返回错误就看不到文件了
接下来我们找到关键的LOAD DATA INFILE数据包,第一个包看起来比较正常,是客户端发起的Request Query,如果你无法使用LOAD DATA INFILE语法的话,考虑在连接 MySQL 的时候加上--enable-local-infile选项,或者设置local_infile全局变量为ON
1.请求包

2.Response TABULAR

3.返回文件

由此,可以看到客户端在发送查询后,服务端返回一个Response TABULAR指定一个文件后,客户端把此文件发送给了服务端。

*  客户端: 我要将`/etc/passwd`的内容插入test表中
*  服务端: 好的,把`/etc/passwd`文件给我
*  客户端: 这是文件内容

这流程可以读文件的前提应该是客户端发送一个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 请求(即Response TABULAR),不一定非要是在LOAD DATA LOCAL的时候。但是必须要执行一个语句(例如:select * from user)

分析数据包

要构造的包一个是Server Greeting一个是Response TABULAR

1.Server Greeting包构造 文档
(其实直接扒在,在改一下细节就完事了)

1
2
3
4
5
6
7
8
9
10
11
'\x0a',  # Protoco
'5.7.22' + '\0', # Version
'\xc8000000' # Thread ID
8位随机数 + '\0' # Salt
'\xff\xf7', # Capabilities, CLOSE SSL HERE!
'\x08', # Collation
'\x02\x00', # Server Status
'\xff\x81\x15'
'\x00' * 10
8位随机数 + '\0'
"mysql_native_password" + "\0"

2.Response TABULAR构造 文档

1
0c 00 00 01 fb 2f 65 74    63 2f 70 61 73 73 77 64    ...../etc/passwd

动手写poc找轮子

传送门
已经有写好的了,只需要改改端口,改改想读的文件就可以了

参考文档

https://lightless.me/archives/read-mysql-client-file.html#_label2
http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/