PHP2Shell 炸了:CVSS 9.2,公开前一天就有人在打,而这两个洞在代码里躺了十年

先说结论:PHP 出了一个 CVSS 9.2 的未授权远程代码执行,编号 CVE-2026-109618 和 CVE-2026-109619,人送外号 PHP2Shell。10 月 20 日公开,10 月 21 日 14:00 UTC 出补丁,而亚马逊的蜜罐在 10 月 17 日——公开前四天——就记录到了利用尝试。

比这更难看的是另一件事:这两个洞最早能追到 PHP 5.4,也就是说它们至少在代码里躺了十年以上。而且 2024 年就有 PHP 核心开发者审计时发现了 OOM 那条路径,团队开会讨论怎么修,没达成一致,然后就没修。理由是当时没人认为能真的写出利用。

这句话现在看起来特别讽刺。写不出来的原因不是洞不重要,是这条链太复杂,复杂到超出人类研究者的实际能力边界。然后 AI 来了,把它写出来了。

PHP2Shell 漏洞封面:影响范围与暴露主机

一、先把「多国紧急响应」这句话拆开看

标题党最爱的说法是「全球拉响警报」。这次还真不是夸张,但警报的成色得分清楚。

  • PHP 官方:10 月 20 日先发预告,说 21 日 14:00 UTC 出安全版本,如果细节提前泄露或出现野外利用就提前发。结果 CVE 编号当天就被人捅到 Hacker News,原定 10 月 22 日的发布被迫提前一天。
  • CERT-EU:发布 advisory 2026-018,把两个 CVE 都列进去了。
  • Cloudflare:CTO Dane Knecht 10 月 21 日直接说「已在看到早期攻击浮现」,WAF 规则全量下发,包括免费用户。但他自己强调这只是 stopgap,真正的解法是打补丁。
  • 亚马逊威胁情报:MadPot 蜜罐 10 月 17 日就抓到尝试,21 日又抓到一批,payload 和基础设施指向多个不同的攻击方。原话是 php2shell「已经在被广泛利用」。
  • watchTowr:两个洞都复现了,同时观察到针对两者的利用尝试。

所以「已发现攻击」不是渲染,是事实。而「多国紧急响应」也不算吹——只是这个响应的主体是厂商、CDN 和应急组织,不是哪个国家的政府在开发布会。

二、两个洞,两种完全不同的死法

很多人以为是一个洞两个编号,不是。这是两条独立的攻击路径,各自 CVSS 9.2。

两个漏洞的技术路径对比

CVE-2026-109618:内存耗尽的时候炸

PHP 在内存分配失败时会中断请求处理。问题出在:这个时候内部的请求数据可能只初始化了一半,而随后的清理逻辑会把这块没初始化完的烂数据当成有效数据来用。

触发方式很朴素:构造 multipart 请求,把内存撑爆。诡异的地方在于,请求体积看起来完全可以符合你配置的上限——它撑爆的不是你设的 post_max_size,而是解码和内部处理环节的消耗。

最狠的是 mod_php。Apache 的 mod_php 在请求启动失败时仍然会执行清理,所以这条链能在任何应用代码运行之前完成。你 PHP 代码写得再干净、再没有漏洞,也拦不住。

PHP-FPM 在启动失败时会直接杀掉 worker,恰好切断这条链,所以官方说 mod_php 风险最高。但注意——这不代表 FPM 就安全,官方明确说 FPM 在成功启动之后仍有被利用的可能。

CVE-2026-109619:请求之间的脏状态

这个更阴。PHP 会复用 worker 进程处理多个请求。上一个请求释放掉的内存,指针还留在内部状态里;下一个请求进来,在正常初始化把它清掉之前,先把这块悬空地址读了。

致命错误(内存耗尽、执行超时)会打断状态清理。更骚的是,shutdown 期间的某些非致命诊断,还会把已经重置的错误状态重新写回去。

官方确认的路径包括:PHP 8.5 上启用 fatal_error_backtraces(默认开)时通过致命错误回溯的 RCE,以及 mod_php 和 FPM 上的 session 生命周期 RCE。session.upload_progress 默认开启,可以充当脏状态的早期消费者——而且这一步根本不需要应用调用 session_start()。

这个洞还附带内存泄露。泄露的是什么?是进程内存里其他请求的密码、token、API key、证书。Wiz 直接拿 Heartbleed 来类比,这个比喻不算过分。

三、时间线,比标题更值得看

PHP2Shell 事件时间线:从 2024 年搁置到 10-17 野外利用
时间发生了什么
2024 年PHP 核心开发者审计时发现 OOM 那个 bug,团队对修法没共识,搁置
2026-08Calif 的 Ryan Austin 用 OpenAI GPT-5.6 Sol 找出漏洞;Wiz 独立发现
2026-10-17亚马逊 MadPot 蜜罐记录到利用尝试,比公开早四天
2026-10-20CVE 编号在 Hacker News 和社交媒体泄露,PHP 发预告
2026-10-2114:00 UTC 发布 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35

10 月 17 日这个日子必须单独标出来。公开日是 20 号,但攻击 17 号就发生了。亚马逊的建议很直接:排查起点不要设在披露日,往前推到至少 10 月 17 日。

至于攻击者怎么提前拿到信息的,亚马逊说「不清楚」。这事儿没法深究,但你得接受一个现实——「披露日」从来不是攻击开始的那天,只是你终于知道的那天。

四、这次真的是 AI 挖出来的

Wiz 的博客里有句话我读了两遍:「这些底层缺陷已经存在了几十年,但要证明它们可被利用,需要一条异常复杂的步骤链,处于人类研究者实际能力边缘。前沿 AI 模型大幅降低了这个门槛。」

具体点:Calif 的研究员 Ryan Austin 是在 OpenAI 的「Patch the Planet」项目里,用 GPT-5.6 Sol 找到的。Wiz 独立发现了同一批问题。为了打通利用,得把多个缺陷串成一条链,还要针对每个目标的内存布局反复调试适配——Wiz 说前沿模型让他们在几小时内就能为不同应用开发出可用利用。

这件事的意义不在「AI 又赢了一次」。意义在于「复杂性」这道护城河正在失效。

过去二十年,很多老漏洞之所以没被打,不是因为它们不严重,是因为利用门槛太高——需要顶级研究者投入几周,还需要一点运气。所以大家心照不宣地把它们归到「理论上有风险」那一栏。现在这个护栏没了。

那些躺在你系统里、被评估为「利用难度高、暂不处理」的十年老洞,评级得重做了。

五、你该升到哪一版

PHP 各分支修复版本对照表
分支受影响版本处置
PHP 8.5< 8.5.12升到 8.5.12
PHP 8.4< 8.4.27升到 8.4.27
PHP 8.3< 8.3.36升到 8.3.36
PHP 8.2< 8.2.35升到 8.2.35
PHP 7.4 / 8.0 / 8.1全部官方无版本发布,只有源码级 backport
PHP 5.4 – 7.3全部EOL,官方不给修,只能自己升或找厂商

几个实操提醒:

  • Linux 发行版和 LTS 厂商提前拿到了补丁,用发行版包的去查你们厂商的 advisory,别急着源码编译。
  • 用 rpms.remirepo.net 的注意:PHP 官方明确说了那个源在 10 月 21 日不会有更新,让你换成发行版包或者自己从源码编。
  • PHP 8.5 的 Windows 二进制也在官方下载页,别说「Windows 没法升」。
  • 别以为跑在容器里就没事——容器镜像里的 PHP 版本该查还得查。

六、上不了补丁,就先做这四件

先声明:下面这些没有一条能让你变安全。PHP 官方的原话是「减少对特定攻击路径的暴露,但不使安装变安全」。它们的价值是给你争取打补丁的时间。

四条临时缓解措施及其限制

1. 把 memory_limit 设成 -1

目的:干掉那个可预测的「PHP 内存上限失败」,也就是 CVE-2026-109618 已确认利用所依赖的触发条件。

关键在怎么设:要在应用改不动的地方设,比如 FPM pool 的 php_admin_value 或 Apache 配置。设完必须检查没有任何 pool、目录、应用设置把有限值又加回来。然后重启每一个 worker。

代价说清楚:你去掉的是 PHP 自己的内存护栏,底层分配失败仍然可能走到那条危险路径。所以还得配容器或 cgroup 限制兜底——但只能用「只杀受影响 worker」的策略,千万别用 RLIMIT_AS 或 RLIMIT_DATA,那两个恰恰会制造出漏洞需要的那种分配失败。

2. 把 post_max_size 压小

不传文件的站点设 8M,要传文件的设 32M,并保证 upload_max_filesize 比它小。同时在 Web 服务器或代理层加限制——解码后的请求体积、字段数量、multipart part 数量、header 数量、嵌套深度。这些限制必须覆盖那些没有有效 Content-Length 的请求,否则构造一下就绕过去了。

3. 关掉 session.upload_progress

session.upload_progress.enabled = 0

写在 php.ini、FPM pool 或服务器配置里,必须早于请求解析生效。用 ini_set() 或者 FPM 的 .user.ini 都太晚了——那时候状态已经脏了。改完同样要重启所有 worker。

4. PHP 8.5 单独再关一个

fatal_error_backtraces = 0

这条只堵住已确认的致命错误回溯路径,其他变体不管。同样要求管理员级别设置 + 重启 worker。

另外官方还提了一条很多人会忽略的:修掉那些攻击者能触发的致命错误和执行超时,包括回调、上传、导入处理、清理阶段的失败。还有,把逐请求施加的过时或非法配置项删掉——它们会在初始化之前吐诊断信息,正好喂给漏洞。

最后这句最容易被误解:用 error_reporting、display_errors 或者 @ 把诊断藏起来没用。藏的是显示,不是发生。

七、这件事真正的教训

我不想写成「赶紧打补丁」就完事。补丁当然要打,今天就打。但有些判断得改。

  1. 「利用难度高」不再等于「可以先放着」。PHP 这个洞的利用链复杂到需要 AI 帮忙,而 AI 已经帮上了。你资产清单里那些标着「理论风险」的老洞,评级标准该重新过一遍。
  2. 语言运行时是单点。WordPress、Drupal、Joomla、Magento、MediaWiki 全跑在 PHP 上,你的应用代码审计做得再干净,PHP 核心出问题照样一锅端。基础设施层的补丁节奏,得和应用层分开管。
  3. 「应用代码没跑就被打穿」这种场景,WAF 只能拖延。Cloudflare 自己都说了是 stopgap。把 WAF 当解决方案的,等于把命交给规则覆盖率。
  4. 国内用 PHP 的老站点非常多。那些跑着 PHP 5.6 / 7.0、早就没人维护、挂在某个云主机上的站,就在 1.3 到 190 万这个暴露面里。它们不会收到任何通知。

数据口径留个记录:W3Techs 说 PHP 占已知服务端语言的 69.3%,Wiz 说 70%;暴露主机数,安全研究者 Silas Cutler 的粗估是 130 万台以上,Henk Poley 的 Shodan 搜索是 190 万台以上。这些数字口径不同,别当精确值用,但量级是一致的——百万级,全球范围。

还有一个细节值得记一下:CVE 编号泄露时,跟着流出的 CVSS 分数写的是 10.0,PHP 官方后来确认那个分数是错的,实际是 9.2。这种细节没人会专门辟谣,但它在传播里会一直存在。看到 10.0 的说法,你就知道来源是哪一波。

一个躺了十年的洞,两个月的 AI 辅助研究,四天的提前利用,一天的补丁窗口。这个时间尺度,就是接下来所有基础软件的常态。

现在就去查版本。php -v,或者看你容器镜像的 tag。别等明天。

暂无介绍....

延伸阅读:

PHP2Shell 炸了:CVSS 9.2,公开前一天就有人在打,而这两个洞在代码里躺了十年

CVE-2026-109618 和 CVE-2026-109619,PHP 5.4 到 8.5 全线受影响,未授权 RC...

itadol5j
2026年10月22日
76.2 万条微信全导出来喂给 AI:最难的压根不是 AI

76.2 万条消息、3675 万字、十年记录。导出、清洗、分块、向量化、混合检索,五步管道全流程,外加五个必踩的坑。还有...

itadol5j
2026年10月20日
opencode-models-discovery 2.0.0 发布:配置形状全换,OpenCode v2 正式转正

九种元数据格式、原生 /connect 凭证、宿主托管缓存。从 v1 迁到 v2 的配置字段对照和四条检查清单都在这里。

itadol5j
2026年10月20日
我蹲了半个月,Gemini 4 Argon 今天凌晨终于全球上线了

先说结果:Gemini 4 Argon 今天(10 月 13 日)凌晨正式全球开放了。我为了它前后蹲了半个月,中间踩了两...

itadol5j
2026年10月14日
REA 爆火后,Agent 时代软件的护城河不存在了?

先说一个可能不太受欢迎的判断:“代码写得复杂所以抄不走”这个护城河,确实塌了。但“软件没有护城河了”是个过度反应——塌掉...

itadol5j
2026年10月13日