一个PHP漏洞,差点端掉全球70%的网站

来源:互联网 时间:2026-10-22

2026年10月21日晚上10点(北京时间),PHP官方发布了四个计划外的紧急版本。

这不是一次普通的补丁日。它是这几年第一次,一个漏洞被直接写进“全球互联网基础设施事件”的级别——NSA的建议是:打不上补丁的系统,先下线。

更要命的一句话来自 Wiz Research:这些缺陷在PHP代码里躺了十几年,把它变成能用武器的是AI。

先做30秒自查,打开终端敲一句:php -v

版本号停在 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 之前,你的站就在射程里。

一、这次出事的是地基,不是房子

两个CVE,社区统称 PHP2Shell,CVSS v4.0 都是 9.2:

• CVE-2026-109618:PHP处理内存耗尽(OOM)时用 longjmp() 提前跳出,此时部分内部数据还没初始化完。请求收尾阶段又把这些无效数据当合法的用,造成内存破坏。

• CVE-2026-109619:工作进程里保留了上一请求的全局状态(错误、会话、OPcache),但底层内存已经释放。下一个请求在正常初始化之前碰到它,就是释放后重用(UAF)。

两个可以串起来打,攻击者发一条特制的 multipart POST 请求即可,无需账号、无需用户交互、无需你的应用本身有漏洞。Wiz 用官方最新镜像,在 wordpress:latest、drupal:latest、joomla:latest 上都打通了未认证RCE。

这里必须把最容易误读的一点讲透:漏洞不在WordPress,不在你的业务代码,不在插件,在PHP本体。你的站点哪怕只输出一句 Hello World,只要跑在受影响版本上就一样危险。WordPress、Drupal 官方都专门发声明澄清过:请把你们的主机商催紧,不是升级CMS就完事。

而且出问题的这段逻辑(multipart 请求解析、session 上传进度)跑在应用代码之前。官方特别点名 Apache mod_php 风险最高:默认配置、常见 prefork 模式下,一个未经认证的请求在业务代码开始执行前就能触发。

比RCE更阴的是配套的内存泄露原语——Wiz 演示了不执行代码、只读内存:把别的请求遗留在进程内存里的密码、登录token、API key、证书,URL编码后塞进你自己的 PHPSESSID cookie 里带走。这条路径不需要应用调用过 session_start()。心有余悸的说法是:你甚至不知道自己已经被读了一遍。

二、躺了十几年,为什么突然能打了

先看量级。VulnCheck 的互联网测绘口径:识别出入口网 PHP 主机 2,608,039 台,其中 99.998% 被判断为“已受影响或可能受影响”;按应用算,WordPress 46.9万台、Laravel 12.4万台、Joomla 2.6万台、Drupal 2.4万台。

至于“70%”这个数,来自 Wiz 的标题和 W3Techs 长期口径(在已知服务端语言的网站中,PHP 约占四分之三),不是“全球网站总数”,这个差别值得较真一下。

那为什么十几年没人打得动?

Wiz 的说法是:要串起多个小漏洞、针对不同 PHP 版本的内存布局反复适配调试,这种活儿过去只有世界级团队愿意碰,一做几个月。这次一名研究员配合 Wiz Atlas、Gemini 4 Argon、GPT-5.6 Sol,大约一周走完了。8月19日发现,20日在Drupal上验证未认证RCE,21日打穿WordPress。

几乎同一时间,安全公司 Calif 在 OpenAI 的“Patch the Planet”计划下用 GPT-5.6 Sol 独立发现了同根问题,两边报告最后被 PHP 团队合并进同一批CVE。

PHP基金会自己在复盘里写得比谁都直白:2024年PHP做了多年来第一次外部安全审计(OSTIF组织、Quarkslab执行),当时就有一位核心开发者看到了这个OOM问题的苗头。后来推不动是因为每条修法都疼——改内存管理伤向后兼容,换处理方式引入新DoS面,还有的要大量第三方扩展跟着改,安全团队又是共识制,反复几个月。基金会给这个过程的定性是“一次结构性失败,既有决策流程问题,也有人手问题”。

真正的优先级,是8月外部报告进来之后才确立的。

三、26小时:从泄露到全球警报

时间线是这次事件最戏剧的部分(UTC):

时间

发生了什么

10/20 15:00

CVE编号外流,还带着一个错误的10.0评分

10/20 19:33

PHP在 php.announce 发预告,把发布日从22日提前到21日14:00

10/20 20:00

Calif 误发PoC视频,删得很快,副本已经传开

10/21 07:34

多家主机商向 Patchstack 报告“正在发生的利用”

10/21 07:41

Chainguard 抢先放出含补丁镜像

10/21 13:30-14:00

四个修复版本同时上线

10/21 同日

NSA、CISA、英国NCSC、CERT-EU、BSI、加拿大中心相继发紧急公告

在补丁还没发的时候,已经有国家先把系统停了:荷兰的 DigiD、MijnOverheid、部分议会网站和 Tweakers 直接下线,日本几家大型服务进入紧急维护,日本首相公开呼吁尽快打补丁。

这个动作本身,比任何CVSS分数都更能说明问题。

四、扫描当天就来了

VulnCheck 的蜜罐在10月21日08:37(UTC,早于官方发版)就记录到带 php2shell-scan/109618 这个 User-Agent 的 multipart POST 探测,一个来源IP先后打了188台蜜罐。

17:22,一次更像真攻击的尝试出现:源自河南联通的一个IP,通过 PHP_SESSION_UPLOAD_PROGRESS 种植webshell,随后10次 php://filter 文件读取尝试想把结果读回来——目标路径不存在,全部404,这次尝试失败了。

奇安信CERT在10月22日的通告里把在野利用状态标注为“已发现”,并称已成功复现;德国 RUS-CERT 也报告已验证公开EXP且观测到攻击。Cloudflare 给所有套餐(含免费版)自动上了针对已知利用向量的WAF规则。

值得留一句的是各家口径的区别:OpenAI强调“披露前没有在野利用”,各家观测到的大量是扫描和未成功尝试,已确认的成功入侵目前仍缺乏公开证据。这不构成松气的理由——只说明攻击者还在挑软柿子。

五、先别急着装插件:这些方法没用

这部分是全文最想让你看的,因为网上错误的“自救指南”传播得比补丁还快。

以下统统不解决问题:

官方给的临时缓解,只能减伤、不能免疫(这句话PHP官方在公告里反复强调),而且必须写在 php.ini 或 FPM pool / Apache 配置里,改完重启所有工作进程:

; 只覆盖 CVE-2026-109619 已确认的会话路径

session.upload_progress.enabled = 0

; 仅 PHP 8.5

fatal_error_backtraces = 0

; 针对 CVE-2026-109618:拆掉攻击者可利用的“内存上限”失败点

; 务必用 php_admin_value,别让应用改回去;需配容器/cgroup做可用性兜底

memory_limit = -1

post_max_size = 8M        ; 不需要上传的站;需要上传给 32M

upload_max_filesize = 4M  ; 必须低于 post_max_size

别拿 RLIMIT_AS / RLIMIT_DATA 去“限内存”,官方明确说它会直接造成底层分配失败,恰好重新踩回漏洞路径。社区里最流行的那条 session.upload_progress.enabled=0,也只封 109619 的一部分,对 109618 无效——把它当护身符比不设更危险,因为你以为自己安全了。

六、升级这一步,最容易漏的是“进程”

分支

升到

备注

PHP 8.5

8.5.12

当前主线

PHP 8.4

8.4.27

 

PHP 8.3

8.3.36

 

PHP 8.2

8.2.35

8.2 将于 2026-12-31 EOL,这是最后的升级窗口之一

≤ PHP 8.1

无官方版本

官方只为 7.4/8.0/8.1 提供最小源码 backport,需自行编译或找发行版

打完补丁≠ 修完。

六个高频陷阱:

1. php -v 只代表CLI,FPM、mod_php、容器里的是另一套,必须分别确认(但别把 phpinfo() 长期挂在公网)。

2. 常驻进程不会自己变新:队列worker、Horizon、Scheduler、Octane、FrankenPHP,逐个重启。找残留旧二进制的土办法:ls -l /proc/*/exe 2>/dev/null | grep -i php.*deleted

3. Docker 要重拉基础镜像 + rebuild + 重新部署,只改tag不算;K8s 要确认没有旧 ReplicaSet 还在服务。

4. 发行版是 backport,版本号可能看着没变。apt-cache policy 看候选版本,升级后查 changelog.Debian.gz 里有没有这两个CVE;顺手 apt-mark showhold 一下,被hold的包更新会静默失败。

5. 志愿者仓库 rpms.remirepo.net 当天明确不提供更新,用它的人得换源或自编。

6. 共享主机用户唯一该做的事是去问服务商:“你们PHP到 8.2.35 了吗?”多租户环境要确认每个实例。

然后是回溯排查,把时间线拉回 10月20日 15:00 UTC 之前开始看:

只要出现过上述任一信号,或者你的机器在21日到打补丁之间一直暴露在公网——请假设数据库密码、API key、session 密钥已经被读过,按泄露处理该轮换的轮换;确认可疑就断网隔离、保住日志、重建服务器。

七、那42%升级不了的呢

VulnCheck 的数字里最扎心的一条:100万台以上、约占 PHP 主机 42% 的机器,跑在已经 EOL、官方根本不会发补丁的分支上(PHP 7.4.33 至今仍是单版本占比最高的,17.2万台)。另一份口径(CybelAngel)扫到 224万台公网 PHP 主机,59% 在拿不到补丁的版本上。

这就是所有类似事件的共同结局:知道,和动得了,是两回事。老系统、老CMS、主机商不升、没人敢碰——这条长尾会一直拖下去,拖到下一次类似事件爆发时它们还在那儿。

所以这次真正该被记住的不是版本号,是那句判断:Wiz 说过去大家默认“这漏洞太复杂、短期没人能稳定利用”本身就是一种保护,现在这层垫子没了。“这个洞太难利用”从此不再是一个能写进风险评估的理由。你存量代码里那些“理论上存在、懒得修”的东西,都该按新的利用成本重算一遍。

顺带提醒,同周后端运行时并不平静:nginx 10月14日的 1.30.6 / 1.31.7 修了三处内存安全问题(alias+rewrite堆溢出、map指令、SSI+UAF),Node.js 10月21日的安全版本修了 Brotli 解码越界写。别只补 PHP 不补入口。(这几条我给的是二手信息,动手前请以官方 changelog 为准。)

八、今晚三件事

1. 跑 php -v,把所有对外承载请求的 PHP 实例列出来(含容器、面板内置、子站、ThinkPHP/老后台这类没人认领的),能升就升;

2. 升不了的,按上面官方那几条做减伤,并认真评估要不要临时下线;

3. 把“迁移到受支持的PHP版本”从待办清单里挪到日程表上。

PHP2Shell不会是最后一次。

参考来源

• Wiz Research:PHP2Shell - AI uncovers critical RCE vulnerabilities affecting 70% of the Internet

• PHP基金会 10月21日安全公告与复盘 / GHSA-w8hw-w9fx-j79w / GHSA-6wmf-4rv5-p3rp

• Calif Research:php2shell;OpenAI:Patch the Planet

• VulnCheck:PHP2Shell Vulnerabilities(测绘与蜜罐数据)

• 腾讯云安全中心风险通告;奇安信CERT风险通告

• CERT-EU 2026-018;NCSC / BSI / RUS-CERT 公告;Cloudflare 安全博客

相关文章

标签:

A5创业网 版权所有