PHP 高危 RCE 漏洞排查与加固指南:修复版本、7.4 补丁与临时措施

2026年10月22日 · 3320 字 · 7 分钟 · PHP 网络安全 RCE PHP-FPM 运维实战

面对这次 PHP RCE 漏洞,生产环境应先确认 PHP 版本、Web 运行方式及补丁状态,随后升级修复版本。无法立即升级时,可先评估关闭上传进度、关闭 PHP 8.5 致命错误回溯、调整内存与网关限制,以及减少 Worker 复用等临时措施。临时加固不能代替补丁。

PHP 运行时 RCE 漏洞与安全补丁主题封面

北京时间 2026 年 10 月 21 日夜间,PHP 官方安全团队发布了一则最高级别的紧急安全通告(Security Advisory):

官方正式修复了两枚严重的未授权远程代码执行(RCE)漏洞。

更夸张的是,除了正在维护的 8.2 到 8.5 版本外,官方甚至破天荒为早已停更(EOL)数年的 PHP 7.4、8.0 和 8.1 提供了源码级 Backport 补丁。

PHP RCE 漏洞为何能在业务代码执行前触发

根据官方通告,这次修复的两枚高危漏洞分别是:

CVE-2026-109618

OOM 内存破坏导致的远程代码执行(RCE via OOM corruption)。

CVE-2026-109619

常驻 Worker 全局陈旧状态残留导致的堆释放后使用(RCE via stale global state)。

这两枚漏洞最危险的地方在于:未授权、预执行。

什么叫预执行?

以往很多业务层面的安全漏洞(比如 SQL 注入、反序列化、文件上传),好歹需要攻击者的请求进入具体的 PHP 业务代码,经过某个存在缺陷的 Controller 或函数才会暴发。

但这次的漏洞发生在 PHP 内核接收并解析 HTTP 请求的最早期阶段。

特别是在使用 Apache mod_php 的环境下,官方已经验证了完整的 Exploit 概念验证(PoC):

一个未经身份验证的外部请求,在服务器还没开始执行你写的任何一行应用代码(index.php)之前,就已经在底层完成了攻击与指令执行。

哪怕你的 Laravel、ThinkPHP 或 WordPress 权限卡得再严死,只要底层的 PHP 运行时中招,整台服务器的 Web 权限就可能瞬间失守。

CVE-2026-109618 与 CVE-2026-109619 的触发机制

两枚漏洞分别涉及 OOM 时的请求清理,以及常驻进程跨请求的全局状态。

漏洞一:OOM 触发内存破坏

CVE-2026-109618

在 PHP 过去的内存管理机制中,当单次请求遭遇内存超限(OOM,即超出 memory_limit)时,PHP 内部会调用 C 语言的 longjmp() 机制强行中断当前的执行流程,直接退出当前上下文。

问题恰恰出在请求刚到达的初始化阶段:

  • 当服务器接收一个 multipart/form-data(常见于表单和文件上传)请求时,PHP 底层的数据结构处于“已分配部分内存、但尚未完全初始化”的中间脆弱状态。
  • 攻击者可以故意构造畸形的 HTTP 请求包——例如不声明合法的 Content-Length 绕过早期的尺寸检查,或者在单个 part 里塞进成千上万个冷门 Header,又或者构造层层嵌套的空文件字段。
  • 这会导致 PHP 在解析这些请求元数据时,内存消耗瞬间飙升,并在最关键的初始化缝隙中精准触发 memory_limit 报错。
  • longjmp() 随即粗暴跳出。此时内存处于非法破损状态,紧接着服务器调用请求清理函数(Request Shutdown)时,误把这些未初始化的野数据当成正常结构处理,直接造成内存破坏并走向远程代码执行。

官方怎么修的?

在新版本中,PHP 彻底剔除了 OOM 处理中的 longjmp() 机制。

改为在虚拟机的安全执行检查点(VM safe point)执行延时的软性平滑退出(soft OOM);如果内存消耗继续突破更高的安全底线,则直接通过操作系统的 _exit() 杀掉进程,绝不让清理流程去触碰残缺状态。

漏洞二:Worker 残留“幽灵指针”

CVE-2026-109619

现代生产环境为了性能,大多采用常驻进程模型(比如经典的 PHP-FPM 多子进程 pool,或 Apache Prefork)。

一个 Worker 进程不会处理完一个请求就自杀,而是常驻内存,源源不断地接待下一个请求。

但在处理上一个请求(Request A)时,某些全局变量(Global State)会暂存指向该请求私有堆内存的指针:

  • 如果 Request A 在运行过程中遭遇了致命中断(比如超时 max_execution_time、文件引入失败、编译错误或 OOM),导致清理函数遗漏了对全局状态的重置;
  • Request A 结束后,其私有内存被操作系统释放;
  • 但 Worker 进程的全局指针里,依然死死记录着那块已经被释放的内存地址!
  • 当该 Worker 接着接听下一个请求(Request B)时,在 Request B 还没正式完成初始化之前,某些早期逻辑(如解析 INI 配置抛出的警告,或是默认开启的 Session 上传进度监控)会错误读取这个残留指针,从而触发典型的堆释放后使用(Use-After-Free,UAF),最终实现可控代码执行。

在 PHP 8.5 环境下,只要开启了 fatal_error_backtraces,这个漏洞就能被稳定利用。

而在 8.2 ~ 8.4 中,即使业务完全没有调用 session_start(),仅仅因为底层启用了 session.upload_progress.enabled,就足以沦为攻击者的消费跳板。

受影响的 PHP Web 环境与修复版本

先看官方明确给出的风险范围:所有对外提供 Web 服务的 PHP 运行环境均在风险之列,包括:

  • Apache mod_php(风险等级最高,存在已验证的 0day 利用链)
  • PHP-FPM(绝大多数 Nginx + PHP 生产架构的标配,跨请求状态利用已被证实)
  • FrankenPHP(Go 语言驱动的现代化 PHP 服务器,调用 shutdown 逻辑同 mod_php 类似,高度敏感)
  • LiteSpeed / LSAPI 与 php-cgi

官方补丁版本清单

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

各主流 Linux 发行版(Ubuntu、Debian、CentOS/RHEL 等)已收到上游补丁,建议直接通过 apt update && apt upgrade 或 yum update 刷新官方镜像源。

使用第三方 RPM 源的用户请留意:

官方在公告中特意点名了大家常用的 rpms.remirepo.net(Remi 源)。由于 Remi 是志愿者维护,官方公告称今天该源可能无法第一时间同步打包最新修复。

如果你依赖 Remi 源,建议临时切换到源码编译或关注其更新动态。

PHP 7.4 / 8.0 / 8.1 的补丁

如果你接手的是老项目、遗留系统,短时间内根本无法平滑升级到 PHP 8.2+,PHP 官方这次在 GitHub 源码仓库罕见提供了最小 Backport 分支:

使用 git clone 拉取对应分支,将补丁打入源码后重新编译:

  • PHP-7.4-CVE-2026-109618-109619
  • PHP-8.0-CVE-2026-109618-109619
  • PHP-8.1-CVE-2026-109618-109619

这些 Backport 分支面向暂时无法升级的遗留系统,应结合现有构建流程编译和部署。

无法立即升级时的四项临时加固措施

升级底层二进制包可能涉及服务重启或依赖冲突。如果今天白天业务高峰期不便直接升级,官方和安全团队给出了以下几项应急止血方案。

请注意:临时方案只是切断了已知可控的攻击链路。

唯一彻底消除隐患的方案只有升级打补丁。

第一步:关闭 Session 上传进度

绝大多数现代业务系统都有自己独立的 OSS/S3 直传或专有上传接口,PHP 原生的 session.upload_progress 几乎用不上,但它恰恰是这次跨请求 UAF 最容易被利用的入口。

直接在全局 php.ini 或 PHP-FPM pool 配置中关闭它,并重载 FPM:

session.upload_progress.enabled = 0

**配置位置:**全局 php.ini 或 FPM pool。

使用 ini_set() 或 .user.ini 无效。

第二步:关闭致命错误回溯

如果是正在尝鲜 PHP 8.5 的团队,请确保在配置中关掉该项:

fatal_error_backtraces = 0

这可以直接掐死针对 8.5 最成熟的那条 PoC 链条。

第三步:调整内存与网关限制

CVE-2026-109618 依靠的是故意把 PHP 内部内存撑爆来触发 longjmp():

① 设置 memory_limit = -1

通过 FPM 的 php_admin_value[memory_limit] = -1,不给攻击者在 PHP 内部精准触发 OOM 的支点。

② 在 Nginx 或 WAF 网关层卡死请求体

  • 非上传接口将 post_max_size 限制在 8M,上传接口限制在 32M。
  • 检查 Nginx 配置,强制开启请求头数量、请求大小限制,过滤掉缺少 Content-Length 的畸形 chunked 请求。

③ 利用 Docker / cgroup 作为外部防线

为容器设置内存上限(如 2G),超出时直接让宿主机 OOM-Killer 彻底干掉容器进程,绝不使用 RLIMIT_AS。

第四步:FPM 一次请求一换进程

如果你的服务器配置充裕,但极度担心跨请求的 UAF 攻击:

可以在 PHP-FPM pool 配置中临时设置:

pm.max_requests = 1

这意味着每个 FPM Worker 进程只处理 1 个请求后就立即退出并重建。

虽然这会带来微小的进程创建开销,但在逻辑上它从物理层面直接粉碎了一切跨请求(Cross-Request)全局状态残留与 UAF 的可能。对于无法升级又身处险境的系统来说,这是最硬核的一道临时护城河。

生产环境排查与升级清单

对仍在运行的老服务,先确认实际 PHP 版本和部署方式,再安排补丁窗口:

  1. 检查一下线上 PHP 的具体版本号;
  2. 关闭用不到的 session.upload_progress;
  3. 安排一次非高峰期的补丁升级或容器镜像更新。

临时加固用于争取升级时间;补丁升级或容器镜像更新仍是最终处理措施。

常见问题

没有调用 session_start(),是否仍需检查上传进度配置?

需要。PHP 8.2 至 8.4 环境下,session.upload_progress.enabled 涉及请求早期处理,不能仅凭业务代码未调用 session_start() 排除文中所述风险。

可以只关闭上传进度功能而不升级 PHP 吗?

关闭上传进度功能属于临时缓解措施,无法代替 PHP 补丁升级。还应结合运行版本评估致命错误回溯、内存限制和 Worker 复用配置,并安排升级窗口。