今天(10 月 21 日)14:00 UTC,PHP 官方发布了两个 CVSS v4.0 评分 9.2 的安全补丁。

但这不是一次正常的协同披露。原定 10 月 22 日的发布计划,因为信息在补丁可用前就被泄露,被迫提前了一天。而安全公司 Sansec 的判断更激进:补丁发布后约 15 分钟,大规模攻击就会开始。

这个数字背后逻辑很简单:利用代码(代号 php2shell)早就在那了,只是被道德约束压着;一旦官方公告确认影响范围,武器化成本趋近于零。

这篇文章拆四件事:泄露是怎么发生的、漏洞大概率在哪、为什么这次特别麻烦、以及你现在该做什么。


一、时间线:一次被打破的 embargo

协同披露(coordinated disclosure)的核心价值,是让发行版和托管商在公告发布的同一时刻就能分发补丁。这个缓冲一旦消失,就会出现一个无补丁的裸奔窗口。

这次事件的时间线:

时间(UTC) 事件
10-20 之前 漏洞处于 embargo,原定 10-22 协同披露,发行版已拿到补丁
10-20 晨 Hacker News 出现 "Tell HN" 帖,引用"可靠消息源"称有影响 PHP 5+ 的 RCE,发帖者自认没证据
10-20 帖子被 HN 下线,但截图已在 X / Mastodon 扩散,Kevin Beaumont 等人转发
10-20 研究员 Kirill Firsov 放出演示视频,攻击链命名 php2shell,署名 LCFR 与 Calif.io
10-20 watchTowr 确认漏洞真实,复现了 CVE-2026-109618
10-20 PHP 安全团队发预警,补丁提前到 10-21 14:00 UTC
10-20 CERT-EU 发布公告 2026-018
10-21 补丁落地:PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35

PHP 官方公告原文写得很克制:

我们保留在漏洞细节公开、或出现野外利用证据时提前发布的权利。

这句话在 10-20 就兑现了。


二、漏洞大概率在哪:session upload progress 的 UAF

先说清楚:截至本文写作,PHP 官方尚未公布 root cause。以下是社区分析(奇安信、上海交大网络信息中心等)的技术假设,最终以官方公告为准。

2.1 攻击面:php_session_rfc1867_callback

分析指向 session upload progress 功能的处理路径,核心函数 php_session_rfc1867_callback(位于 ext/session/session.c)。

这个功能是 PHP 5.4 引入的,用于让前端显示上传进度条。它的工作机制有三个特点,叠加起来很危险:

  1. 客户端在 multipart/form-data 请求里带上 PHP_SESSION_UPLOAD_PROGRESS 字段,PHP 在解析 multipart 请求体的过程中(不是处理完之后)就开始写 session 数据;
  2. 进度更新发生在应用脚本执行之前——也就是 RINIT 之后、你的代码运行之前;
  3. 该功能由 session.upload_progress.enabled 控制,php.ini 默认值是 On。

默认开启 + 不需要应用写任何代码 + 解析请求时就触发 —— 这三个条件意味着,大量"从没用过进度条"的部署也在攻击面里。

2.2 机理:生命周期错位导致的 UAF

php_session_rfc1867_callback 在 multipart 解析过程中会触发多次 session 状态切换(save/open/close 与引用计数操作)。在特定请求顺序和状态组合下:

  • 某些 session 相关内存对象(session 结构、上传进度元数据)在后续处理到达前被提前释放;
  • 随后的进度更新逻辑仍持有已释放对象的引用,再次访问形成 Use-After-Free;
  • 观测特征:release 构建下表现为 PHP 工作进程崩溃(FPM master 重启,看起来像"上传失败");debug/ASAN 构建下能看到明显的引用计数异常。

奇安信把成因映射到 CWE-94(代码注入) 与 CWE-787(越界写入)。这个组合的读法是:底层是 UAF 类内存破坏,越界写是 UAF 被利用后的典型效果,顶层表现才是任意代码执行。

UAF 能否稳定利用,取决于堆布局可控性。而在 session upload progress 场景下,攻击者通过控制请求体大小、multipart 分片、并发连接,可以相当程度地操控堆分配序列(heap grooming)——这正是历史上大量 PHP UAF 能被稳定武器化的原因。

2.3 为什么有 2 个 CVE

目前无法确认 CVE-2026-109618 与 CVE-2026-109619 的确切对应关系。合理推测是:同一回调路径上的两个独立缺陷(比如 open handler 和 update handler 各一处),或者触达同一 UAF 的两条不同路径。

一个旁证:php2shell 演示视频引用的受影响版本从 PHP 5.4.0 起,而 5.4.0 恰好就是 session upload progress 引入的版本。时间线上完全自洽。

2.4 触发条件

CERT-EU 说漏洞可能允许无需认证的远程代码执行。这与攻击面分析一致——触发只依赖 HTTP 请求本身,不依赖业务逻辑或登录态。

需要满足:

  1. 能向目标 PHP 服务发 HTTP 请求(即公网可达);
  2. PHP 版本受影响,且 session.upload_progress.enabled 未关闭(默认开启);
  3. 若配置过 session.upload_progress.prefix/name,字段名需匹配(默认配置下都能满足)。

但请注意:这些是从攻击面推导的推断。在官方公告出来前,不能因为"我的配置不符合"就断定安全。


三、为什么这次特别麻烦

3.1 补丁真空:EOL 分支没得打

PHP 分支 当前版本(2026-09-24) 修复版本 状态
8.5.x 8.5.11 8.5.12 安全支持中
8.4.x 8.4.26 8.4.27 安全支持中
8.3.x 8.3.35 8.3.36 安全支持中
8.2.x 8.2.34 8.2.35 仅安全修复
8.1 及更早 8.1.33(2025-12-31 EOL) 无补丁 已 EOL
7.x / 5.x — 无补丁 已 EOL

三个要点:

  1. "影响 PHP 5+ 所有版本"来自泄露信息(php2shell banner 和 HN 帖),PHP 官方从未证实。但结合疑似触发点在 5.4 引入的功能上,这个范围有技术合理性。
  2. 官方补丁只覆盖受支持的 8.x 分支。PHP 5/7/8.0/8.1 处于补丁真空——EOL 系统如果公网可达,唯一安全选项是迁移或隔离。
  3. 用 apt/yum 装的 php-fpm 别自己编译。发行版通常会给旧分支做 backport,应盯 Debian/Ubuntu/RHEL 的 DSA/USN/RHSA,而不是 php.net 的版本号。

3.2 补丁的"物理位置"很麻烦

PHP 是 WordPress(全球约 40% 网站底层)、Drupal、Joomla、Magento、Laravel、MediaWiki 以及绝大多数共享主机的运行时。有非官方估计称互联网上直接暴露的 PHP 主机约 130 万台量级。

但比主机数量更麻烦的是补丁要打在哪:

  • 应用层漏洞(某个 WordPress 插件 RCE):升级插件即可,影响面限于用这个插件的人;
  • PHP 核心漏洞:修复点在服务器 / 容器 / 镜像层面。

这意味着 WordPress 站长常用的"一键更新插件"完全无济于事。你必须触达:每一个 FPM 容器、每一个主机镜像、每一台内嵌 PHP 的第三方设备(NAS、负载均衡器、备份一体机里都可能藏着一份 PHP)。

Huntress 特别提醒要排查厂商软件内嵌的 PHP —— 这类资产通常没有版本管理责任人,恰恰最容易漏。


四、现在该做什么

立刻(补丁前 / 无法立即升级时)

① 关闭 session upload progress(当前最有效的临时措施)

绝大多数业务根本不用上传进度条。在你的 php.ini、.user.ini 或 .htaccess 里:

session.upload_progress.enabled = Off

然后重载 FPM:

systemctl reload php8.3-fpm    # Debian/Ubuntu
# 或
systemctl reload php-fpm       # RHEL/CentOS

这条切断的是已验证的攻击路径,但不能替代补丁。

② 网关层拦截

在 WAF / 反向代理层,保护那些本来就不需要文件上传的端点。可以拦截请求体含 PHP_SESSION_UPLOAD_PROGRESS 的请求。代价是会误伤真正用进度条的业务,需评估。

③ 隔离 EOL 分支

PHP 8.1 及更早版本立即下线公网暴露面,改走 VPN / IP 白名单,直到完成迁移。

④ 保留并监控日志,重点看:

  • PHP-FPM worker 异常退出(segfault)、Web 崩溃——UAF 利用失败的典型痕迹是大量 worker 无故重启;
  • PHP 进程派生的异常子进程、异常文件写入(WebShell 落盘特征);
  • 高频、畸形、含 PHP_SESSION_UPLOAD_PROGRESS 的 multipart 访问记录。

补丁发布后(T+0 ~ T+1h)

  • 只认 php.net 官方公告的受影响版本与修复版本,不信第三方转述
  • 按资产清单灰度推送,优先公网暴露面
  • 发行版用户盯 DSA/USN/RHSA;自编译用户从 php.net 拉源码
  • 升级后验证 php -v 实际生效 —— FPM reload ≠ restart,注意 opcache 和长连接 worker

后续(T+1h ~ T+7d)

  • 基于上面的特征做日志狩猎,排查 10-20 以来的可疑 multipart 流量
  • 关注 CISA KEV 目录的后续确认,修正技术假设
  • EOL 分支制定迁移时间表,别把"临时隔离"变成永久状态

五、几点想法

Embargo 机制比想象中脆弱。 这次泄露源头只是一篇"无法定位原文"的报告,加一条自认没证据的 HN 帖。信息一旦进入口头传播链,embargo 就名存实亡。PHP 团队选择提前一天发补丁而不是硬扛原时间表,是正确的危机处理——披露纪律已被打破时,缩短裸奔窗口比维护流程仪式更重要。

"准备型公告"正在成为新范式。 在补丁还用不了的时候提前 48 小时发"prepare now",这在 PHP 历史上很少见。但它承认了一个现实:从公告到武器化的时间已经从数周压缩到分钟级,防御方唯一能准备的时机在公告之前。

EOL 长尾的清算时刻。 每次这种事件都在给"还能跑就行"的系统记账。8.1 及以下无补丁可打,运营方被迫在漏洞窗口和业务连续性之间选——而这个选择本该在版本 EOL 那天就做完。

信源纪律。 这次网上流传的 CVSS 10.0(官方是 9.2)、"所有版本受影响"(实际只有受支持分支有补丁),落差再次说明:以官方公告为准,对泄露信息保持"合理怀疑 + 按最坏情况准备"的双重姿态。


参考来源

  1. PHP 官方公告:Upcoming Critical PHP Security Release(php.net,2026-10-20)
  2. Tenable:php2shell (CVE-2026-109618, CVE-2026-109619) Critical PHP RCE FAQ
  3. Huntress:Rapid Response: php2shell, Leaked Critical PHP Vulnerabilities
  4. Beazley Security Labs:BSL-A1233 Advisory
  5. CERT-EU Advisory 2026-018
  6. 奇安信安全内参:PHP 远程代码执行漏洞安全风险通告
  7. 上海交通大学网络信息中心:关于 PHP Core 存在远程代码执行漏洞的风险预警
  8. Sansec:PHP2Shell Is Coming: Your Patch Window Is 15 Minutes

⚠️ 免责声明:本文成文于补丁发布当日,其中 session upload progress / UAF 部分来自社区分析,尚未经 PHP 官方确认,请在官方公告发布后核验修正。文中配置与命令仅供自有系统防御性使用,请勿用于未授权测试。任何因滥用造成的问题由使用者自负。

如发现漏洞,请通过官方渠道(security@php.net)报告。