利用 PHP7 的 OPcache 执行 PHP 代码
字数 1529 2025-08-29 08:31:41
PHP7 OPcache 代码执行漏洞分析与利用
0x00 OPcache 简介
OPcache 是 PHP 7.0 内置的缓存引擎,通过将 PHP 脚本编译为字节码并存储在内存中来提升性能。关键特性:
- 缓存文件存储在文件系统中,路径由
opcache.file_cache配置指定 - 缓存目录结构镜像 Web 目录结构
- 缓存文件名格式为
原文件名.bin - 每个缓存文件包含
system_id头信息,用于版本兼容性校验
0x01 漏洞利用原理
基本利用条件
- 目标服务器使用 PHP7 并启用 OPcache
- 存在文件上传漏洞
- Web 目录不可写但 OPcache 缓存目录可写
- OPcache 配置满足以下至少一项:
opcache.validate_timestamp = 0(PHP7 默认值为1)opcache.file_cache_only = 1(PHP7 默认值为0)
攻击步骤
-
收集信息:
- 通过 phpinfo() 获取:
- OPcache 缓存目录路径
- Web 目录路径
- 计算 system_id 所需的 PHP 和 Zend 版本信息
- 通过 phpinfo() 获取:
-
生成恶意缓存文件:
<?php system($_GET['cmd']); ?>- 在本地配置相同 PHP 环境
- 访问该文件生成缓存文件(如 index.php.bin)
- 修改文件头中的 system_id 为目标系统的值
-
上传覆盖:
- 将恶意缓存文件上传至目标缓存目录
- 路径格式:
/tmp/opcache/[system_id]/var/www/index.php.bin
-
触发执行:
- 访问对应的 PHP 文件(如 /var/www/index.php)
- 恶意代码将被执行
0x02 高级绕过技术
绕过内存缓存(file_cache_only = 0)
当内存缓存优先时,需要:
- 等待服务器重启使内存缓存失效
- 或寻找框架中不常用的旧文件(如 WordPress 的 registration-functions.php)
- 这些文件不会被主动加载,无内存缓存
- 上传对应的恶意缓存文件后直接访问可触发
绕过时间戳校验(validate_timestamps = 1)
- 针对框架中长时间未修改的文件(如 WordPress 某些 2012 年后未更新的文件)
- 获取目标文件的准确时间戳
- 修改恶意缓存文件中的时间戳(偏移量 34 字节处)与源文件匹配
0x03 防御措施
-
PHP 配置:
- 保持
opcache.validate_timestamp = 1(默认值) - 设置
opcache.file_cache_only = 0(默认值) - 限制 OPcache 缓存目录权限
- 保持
-
代码审计:
- 严格检查文件上传功能
- 移除不必要的旧文件
-
系统加固:
- 确保 Web 目录和缓存目录的适当权限
- 定期更新 PHP 版本
0x04 技术细节补充
system_id 计算
system_id 是以下信息的 MD5 哈希:
- PHP 版本号
- Zend 扩展版本号
- 各数据类型大小
可通过 phpinfo() 获取必要信息后计算得出。
缓存文件结构
- 文件头部包含签名和 system_id
- 时间戳位于偏移量 34 字节处
- 文件内容为编译后的字节码
环境要求
- PHP 7.0 及以上版本
- OPcache 扩展启用
- 缓存目录可写(通常 www-data 用户有权限)
总结
OPcache 的代码执行漏洞展示了即使在没有 Web 目录写权限的情况下,攻击者仍可能通过缓存机制实现代码执行。这种攻击方式特别针对 PHP7 环境,强调了安全配置和权限控制的重要性。防御的关键在于合理的 OPcache 配置、严格的权限管理和及时清理不必要的旧文件。