VPS优惠推送
分享好玩教程

PHP2Shell 应急全记录:官方消息源时间线、不能升级时的缓解措施,以及这些措施挡不住什么

本文于 2026-10-22 15:25 更新,部分内容具有时效性,如有失效,请留言

2026 年 10 月 21 日,大概是最近几年 PHP 生态最忙的一天:两个 CVSS 9.2 的未认证远程代码执行漏洞(CVE-2026-109618 / CVE-2026-109619)在补丁发布前后,全球的运维、主机商、面板厂商几乎都在连夜升级。

官方给这组漏洞起了个名字:PHP2Shell。这篇不重复「怎么查版本」——那一步其实很短:php -v,低于 8.4.27 / 8.3.36 / 8.2.35 / 8.5.12 就说明没打补丁。本文要讲的是另外三件事:官方消息源时间线、不能立刻升级时的缓解措施(附官方原文与实测注解)、以及这些措施到底能挡多少。

先看一句官方原话,这句话定义了整篇文章的基调:

「only an update is a complete solution」 —— 只有升级才是完整解决方案;下面的措施只是降低特定攻击路径的暴露,并不能让安装变安全。

1、为什么这次全球都在熬夜

维度 情况
严重程度 CVSS v4.0 = 9.2,无需任何认证
影响层面 PHP 引擎本身,不是某个应用/插件的漏洞
受影响面 所有「处理 Web 请求」的 PHP:FPM、mod_php、php-cgi、FrankenPHP、LiteSpeed
最危险的情况 mod_php:官方说有演示利用,在任何应用代码执行之前就能触发
利用门槛 官方措辞是「没有简单的利用方法」,但 watchTowr 蜜罐在补丁发布前后已看到在野尝试

换句话说:它不挑目标,也不看你的站有没有装什么插件 —— 只要你的 PHP 在处理外部请求,就在射程内。

2、官方消息源与时间线

一天之内的五个关键点:CF 的防护比 PHP 补丁早了约 9 小时,那半天是唯一的窗口期

这一节是本文最想给你留档的部分,全部给可点开的官方来源:

时间(北京时间) 事件 来源
10-20 前后 漏洞细节与补丁计划提前泄露,安全圈开始预警 Sansec / watchTowr 等
10-21 03:02 Cloudflare 对所有 WAF 用户(含免费版)默认启用防护,比 PHP 官方发布早了约 9 小时 Cloudflare 官方博文
10-21 14:00 UTC
(22:00 北京)
PHP 官方发布 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 php.net 安全公告
同一时间 watchTowr 蜜罐观测到首批在野利用尝试;Cloudflare CTO 确认「早期攻击已经出现」 SecurityWeek
同一时间 官方额外提供 PHP 7.4 / 8.0 / 8.1 的源码 backport(自己编译的人可用) php.net 公告
10-21 22:15 本站服务器完成升级:8.4.26 → 8.4.27,全程中断不到 2 秒 本站实测

两个技术细节值得单独说:

  • CVE-2026-109618(OOM 腐败):内存耗尽时的处理逻辑会中断 PHP,此时请求内部数据只初始化了一半,清理阶段把无效数据当成有效数据处理 → RCE。
  • CVE-2026-109619(全局状态残留):请求私有状态在内存释放后仍然存活,同一 worker 处理的下一个请求可能用到这份陈旧状态 → RCE。

这两个机制决定了后面的缓解措施为什么长那样 —— 它们都是对着「触发条件」打补丁,而不是修根因。

3、不能立刻升级时:官方缓解措施(含实测注解)

官方缓解措施照做,但每一条都有它的边界

以下内容照抄 php.net 官方公告,我只补了中文解释和「坑在哪」。

① 针对 CVE-2026-109618(内存超限)

措施 官方要求 ⚠️ 坑在哪
关闭 PHP 内存上限 memory_limit = -1,用应用无法覆盖的方式设置(FPM pool 的 php_admin_value 或 Apache 配置),并确认没有任何 pool / 目录 / 应用级配置又把它设回有限值 不留限制 = 单请求可能吃光内存 ✗ → 必须配合 cgroup(见下)
限制请求体大小 无上传 post_max_size = 8M;有上传 32M;并保证 upload_max_filesize < post_max_size 单独设 8M 不够 ✗:有实验记录显示 3MB 请求体就打爆了 128M 上限
前置层限制请求结构 在 Nginx / WAF 限制:解码后的请求大小、字段数量、multipart 段数、请求头数量、嵌套深度 这些限制必须也覆盖没有 Content-Length 的请求 ✓(chunked 传输绕过很常见)
容器 / cgroup 限制 用 cgroup 做可用性边界,最好只杀掉出问题的那个 worker 绝对不要用 RLIMIT_AS / RLIMIT_DATA ✗ —— 它们会触发同一个漏洞路径

② 针对 CVE-2026-109619(状态残留)

措施 官方要求 ⚠️ 坑在哪
关上传进度 session.upload_progress.enabled = 0,并重启所有 worker 必须写在 php.ini / FPM pool / 服务器配置里,不能用 ini_set() 或 .user.ini ✗(那时请求解析已经开始)
仅 PHP 8.5 fatal_error_backtraces = 0,重启 worker 只挡「已确认的 fatal backtrace 路径」,其他变体不挡
清理废弃配置 移除那些会在初始化之前就产生诊断信息的、按请求应用的无效/废弃设置 用 error_reporting / display_errors / @ 掩盖是无效的 ✗
修根因 修掉攻击者可达的 fatal error 与执行超时(回调、上传/导入处理、清理逻辑里都算) 这一条最容易被忽略,但它是唯一治本的

⚠️ 三个必须纠正的常见误解

  • 「把 memory_limit 调低更安全」 ✗ —— 官方要的是 设为 -1,因为漏洞触发点正是「撞到内存上限后的处理逻辑」。调低等于主动帮攻击者更快触发。这是中文圈流传最广的错误操作。
  • 「关掉 session.upload_progress 就安全了」 ✗ —— 官方明确写的是「blocks the confirmed session paths but not other variants」:只挡已确认的路径,不挡其他变体。
  • 「设了 8M 就够了」 ✗ —— 8M 是 PHP 默认值,单靠它挡不住,必须叠加前置层限制 + cgroup。

4、这些措施的效果边界

三道闸门:CF 挡特征、PHP 缓解收窄路径、cgroup 兜底,最后才是升级

把它想成三道闸门,而不是一道:

闸门 能挡什么 挡不住什么
Cloudflare WAF(已完成 ✓) 已知的利用特征;免费版也默认开启 新变种;绕过 CF 直连源站的请求 ✗
PHP 缓解配置(本文措施) 已确认的触发路径(OOM 处理、session 路径) 未公开的变体;它只是降低概率,不是修复
cgroup 内存被打爆时保机器不宕 被打中的那个 worker / 那台容器仍然会挂

所以正确的组合是:CF 挡特征 + PHP 缓解收窄路径 + cgroup 兜底存活 + 尽快升级 —— 前三个是买时间,最后一个才是解决。

5、正确的做法:升级(实测 20 秒)

# Debian / Ubuntu(发行版包)
apt update
apt list --upgradable | grep php
apt-get install --only-upgrade 'php8.4-*'

# 重启 PHP 与 Web 服务
systemctl restart php8.4-fpm && systemctl reload nginx

# 验证
php -v

本站实测:从检查到升级完成 约 20 秒,fpm 重启造成的中断 不到 2 秒,nginx 全程正常响应。所以「来不及升级」这个前提,多数情况下其实不成立。

几个升级坑:

  • PHP 8.1 及以下:官方不再维护,只能找发行版 / LTS 厂商要 backport,或者直接升到支持的版本;
  • remi 源用户:官方公告明确说该仓库当天不会有更新 ✗,建议切到发行版包或自己编译;
  • Docker:换镜像 + docker compose up -d 重建容器,不是 restart(restart 只重启进程,镜像还是旧的),重建后进容器 php -v 确认;
  • 升完记得 重启 worker / 容器 ✓ —— 装完不重启,跑的还是旧二进制。

附:PHP 7.4 / 8.0 / 8.1 也有源码 backport(但普通用户用不上)

这是这次事件里最有意思的一个细节:官方公告一边写着「PHP 8.1 及更早版本不再获得更新」✗,一边又在 GitHub 上给这三个版本开了针对本次漏洞的补丁分支 ✓ —— 严格说是「不再发新版本」,而不是「完全不管」。

补丁分支 最新提交 提交说明 日期
PHP-8.1-CVE-2026-109618-109619 1d7dec1 Avoid state corruption via bailout 2026-10-18
PHP-8.0-CVE-2026-109618-109619 82f8f31 Avoid state corruption via bailout 2026-10-18
PHP-7.4-CVE-2026-109618-109619 712e60f Avoid state corruption via bailout 2026-10-18

三个分支都只包含一个针对性提交,提交说明完全一致(「Avoid state corruption via bailout」,避开 bailout 导致的状态损坏);提交日期是 10 月 18 日 —— 比公开披露早了三天,说明官方在发公告之前就已经准备好了。

⚠️ 但它不是给普通用户准备的:分支里只有源码,没有二进制包。要用它得走完整流程:

git clone https://github.com/php/php-src.git
cd php-src
git checkout PHP-8.1-CVE-2026-109618-109619
./buildconf --force
./configure --prefix=/usr/local/php-8.1-patched [换成你自己的编译参数]
make -j$(nproc) && make install

官方对它的定位写得很清楚:「帮助那些从源码构建、或没有 LTS 厂商支持的人」 —— 不是让你在生产机上临时编译玩。

给普通用户的建议:

  • 优先用发行版包 ✓(Debian / Ubuntu / RHEL)—— 厂商会做 backport,比如 Debian 13 直接推了 8.4.27;
  • remi 源用户 ✗ —— 官方公告明确说该仓库当天不会有更新,建议切到发行版包或源码编译;
  • 不要为了省事用旧版本源码补丁硬撑 ✗ —— 8.1 及以下的其他安全问题不会再修,这个补丁只解决这两个 CVE;
  • 8.2 用户也要留意 ✓:官方公告写明 PHP 8.2 将于 2026-12-31 结束支持,到时候连 backport 都不会有。

6、我们这台机器的实际处置

本站的四层处置,每一层都验证过,不是「应该配好了」
层级 做了什么 验证结果
边缘 Cloudflare 托管 WAF(7 条 Anomalous Execution 规则)+ 自定义敏感路径拦截 + 速率限制 规则均 block 且启用 ✓
源站入口 只允许 Cloudflare 回源,其余直连一律 403 直连返回 403 ✓,走 CF 返回 200 ✓
PHP 8.4.26 → 8.4.27 CLI / FPM / OPcache 全部 8.4.27 ✓
后续 每日 webshell 扫描(基线 0)+ 每 10 分钟自动检查补丁 + 备份留档 扫描正常 ✓,自动任务已修掉「不刷新 apt 源」的坑 ✓

顺带说一个我自己踩的坑:自动补丁脚本只查 apt 的本地缓存,从不 apt-get update ✗ —— 等于永远不会发现新版本。这类「看起来在自动、其实没在动」的脚本,比没有更危险。

7、该慌吗

不用慌,但也不能拖。

  • 官方说「没有简单的利用方法」→ 说明目前不是「一条 curl 就打穿」的水平;
  • 但在野尝试已经出现,补丁也放了,逆向分析是迟早的事;
  • 所以判断标准很简单:能升级就升级(20 秒的事);实在不能升,就按第 3 节把路径收窄,并且把升级排进当天日程,而不是"以后再说"。

8、官方来源汇总

(本文技术内容以 php.net 官方公告为准;其余厂商措施仅作补充参考,实施前请自行核对官方原文。)

赞(0)
未经允许不得转载:F12笔记 » PHP2Shell 应急全记录:官方消息源时间线、不能升级时的缓解措施,以及这些措施挡不住什么

评论 抢沙发