10 月 21 日 14:00(UTC),PHP 一次放出四个安全版本:8.5.12、8.4.27、8.3.36、8.2.35。同一天 OpenAI 发了篇博客,标题克制,内容不克制:他们牵头协调了一次横跨多家机构的漏洞披露,对象是 PHP 两个 CVSS 9.2 的未认证 RCE。

图:OpenAI 官方公告卡「Patch the Planet」,本次 PHP 漏洞全球协调披露的官方发布配图
更扎眼的是时间差。据 Sansec 整理的时间线,补丁发布前 6 小时,Cloudflare 已经观测到针对这组漏洞的真实攻击;前一天,漏洞细节在安全圈泄露,watchTowr 确认能打出 RCE。换句话说,公开披露那天,这东西已经有人在实际打了。
70% 这个数字得拆开看
IT之家 10 月 22 日的报道标题是《影响约 70% 网站:PHP 高危漏洞被修复,OpenAI 牵头协调全球发现/修复》。中文报道大多把"约 70% 网站"直接接在漏洞句后面,读起来像七成网站被这两个洞打穿。这层理解不对。
70% 说的是 PHP 本身的地盘。W3Techs 10 月 22 日的统计,在所有已知服务端语言的网站里,PHP 占 69.3%,第二名 JavaScript 只有 8.1%,Ruby 7.1%,Java 5.4%,Scala 5.0%,ASP.NET 4.2%,Python 1.1%。漏洞真正波及的,是跑着受影响版本 PHP 的那些站点,范围落在 PHP 生态内部。
两个事实得分开讲。前者是生态体量,后者是这次的洞。混在一起,数字会被放大成一场不存在的恐慌;也会让另一部分读者觉得跟自己没关系,而只要你在跑 PHP,关系就不小。
漏洞本体:两个 use-after-free,不在你的代码里
网上不少稿子把这组洞写成"URL 解析器缺陷,可导致 SSRF、绕过域名验证"。这个定性在 OpenAI 博文、php.net 公告、Calif 的技术 writeup 三份一手材料里都找不到出处,照抄会翻车。
php.net 官方公告给出的是两个引擎层内存安全问题:
- CVE-2026-109618(GHSA-w8hw-w9fx-j79w),官方描述 "RCE via OOM corruption":PHP 处理内存耗尽时,可以在内部请求数据只初始化一半的情况下被打断,清理阶段把无效数据当有效数据继续用;
- CVE-2026-109619(GHSA-6wmf-4rv5-p3rp),"RCE via stale global state":请求私有状态在自己的内存被释放后仍然存活,同一个 worker 处理下一个请求时,还没走完正常初始化就用上了这些残留状态。
两个的 CVSS v4.0 都是 9.2。

图:Wiz Research 发布的 PHP2Shell 研究封面,直接标注 CVE-2026-109618 与 CVE-2026-109619 两个编号

风险面 php.net 写得很直白:所有服务 web 请求的 PHP 安装都在范围内,PHP-FPM、Apache mod_php、php-cgi、FrankenPHP、LiteSpeed 全算。其中 mod_php 风险最高,官方原话说已经演示出一条利用路径,一个未认证请求就能在任何应用代码执行之前触发攻击。
"任何应用代码执行之前",这句是整件事最难受的地方。业务代码写得再干净、参数过滤做得再严,都躲不开,洞在引擎里,请求进门第一步就中。Calif 实测确认无需登录即可 RCE 的应用有 11 款:WordPress 7.1.2、Drupal 11.4.3、Joomla 6.1.4、MediaWiki 1.46.2、Roundcube 1.7.4、Magento 2.4.9、phpMyAdmin 5.2.3、Nextcloud 35.0.1、Laravel 13.11、Symfony 8.1、WHMCS。原文还有一句更狠的:最早受影响的代码路径能追溯到 2012 年发布的 PHP 5.4.0,默认配置下始终可利用。mod_php 和 PHP-FPM 都跑不掉。

图:Wiz Research 绘制的 PHP2Shell 攻击链示意,特制 HTTP 请求即可对 WordPress、Drupal、Joomla 等 PHP 应用触发 RCE
利用链:先骗过两道资源闸门
技术细节 Calif 的 writeup 写得很完整,值得展开。整条链的目标是拿到一个"可控的 fatal",为此要先绕过两道资源上限。
第一道是 post_max_size。PHP 判断请求体超不超限,比较的是客户端声明的 Content-Length 和 post_max_size 配置,不去核实际消费了多少字节。于是两个口子都开着:Apache 环境下,chunked 编码的 HTTP/1.1 请求、不带长度声明的 HTTP/2 multipart 请求,都能绕过这道比较;如果配了输入解压 filter,压缩后的长度和解码后的流长度同样对不上。
第二道是 memory_limit。在请求总量压在 post_max_size 之内的前提下,用 RFC1867 上传协议里 filename="" 的空 part 反复堆,这种 part 不携带文件数据,却照样吃内存,堆到临界点就够。
拿到可控 fatal 之后才接正题。Calif 找到 2 个 fatal producer 加 3 个可中断点的组合,把异常清理路径上的悬垂内存变成可读写的利用原语,最终实现内存泄露和 RCE。配套利用工具 PHP2Shell 已经公开。
顺着这条链能看到模型参与的具体痕迹在哪。OpenAI 的说法是 Calif 在 GPT-5.6 Sol 协助下发现了其中一个严重漏洞;writeup 里最能体现这种协助价值的,就是上面两步输入构造:枚举 HTTP 方法、压缩 filter、空 part 这类组合空间,恰好是人懒得穷举、模型擅长铺开的活。

实战:查自己、止血、升级
这节给运维和后端,照着做。流程依据 Sansec 的 PHP2Shell 研究报告和 php.net 公告。
第一步,确认版本
bash
php -v
php -v 给的是 CLI 那份二进制的版本,web 请求走的是 fpm 或者 mod_php,两者可能不一样。一台机器装多套 PHP 很常见,得分开查:
bash
# fpm 那份,按实际版本替换
php-fpm8.2 -v
# Debian/Ubuntu 的包视角
dpkg -l | grep -E '^ii php'
# RHEL 系
rpm -qa | grep php
对照的修复版本是 8.5.12、8.4.27、8.3.36、8.2.35,低于这些就要处理。7.4、8.0、8.1 官方已停止常规更新,这次额外提供了最小源码 backport,自己编译的老版本也能拿到修复。
拿一台 nginx + PHP-FPM 8.2 的 WordPress 机器走一遍完整案例:
bash
$ php-fpm8.2 -v
PHP 8.2.28 (fpm-fcgi) ...
8.2.28 低于 8.2.35,中招。WordPress 还在 Calif 实测的 11 款 pre-auth RCE 名单里,默认配置即可利用,不用纠结"我们有没有开上传功能"。
第二步,升级并重启
升级前先看一眼发行版仓库给没给修复包,发行版的包版本号跟上游对不上是常事:
bash
apt changelog php8.2-fpm | head -30
安全更新进仓库有延迟,等不到就先上第三步的止血配置,别干等。
bash
sudo apt update
sudo apt install --only-upgrade 'php8.2-*'
sudo systemctl restart php8.2-fpm
包名按你的发行版仓库调整。重启这步不能省,fpm 是常驻进程,二进制换了、内存里跑的还是旧代码,不重启等于没升。
复查:
bash
$ php-fpm8.2 -v
PHP 8.2.35 (fpm-fcgi)
用 mod_php 的对应执行 sudo systemctl restart apache2。
到这一步,这个案例有了结论:机器此前跑在受影响版本上,补丁发布前处于 pre-auth RCE 暴露状态;升级并重启 fpm 之后暴露解除。顺手翻一下访问日志,看到来源不明、Content-Type 带 multipart 的 POST,按被试探处理。
第三步,暂时升不了就止血
Sansec 给了三条临时缓解,按侵入性从小到大。
nginx 直接拦 multipart 请求:
nginx
if ($http_content_type ~* "multipart/form-data") {
return 403;
}
代价是文件上传全部报废,WordPress 后台传图也会挂,只适合撑过升级窗口。
php.ini 关掉 upload progress、放开内存上限:
ini
session.upload_progress.enabled = 0
memory_limit = -1
memory_limit = -1 要掂量一下。它的逻辑是让 OOM fatal 不再出现,等于把利用链的扳机拆了;但进程失去内存上限,真被大请求打满就轮到 OOM killer 出场,可能把同机其他服务一起带走。机器内存富余再考虑这条。
最粗暴的是入口只放行 GET/HEAD,POST 全拒。API 站能忍,内容站忍不了。
踩坑还有三条。用 rpms.remirepo.net 的注意,这个志愿维护的仓库在补丁发布当天没出更新,php.net 官方的建议是改用发行版包或者自己编译。跑 Docker 的,php:8.2-fpm 这类基础镜像要重新 pull 再重建容器,镜像缓存里还是旧版本,这也是最容易漏的一类资产。多台机器的,别忘了负载均衡后面藏着的那几台,出问题的往往就是它们。
第四步,机器多就借工具
OpenAI 这次配套放了一个 Codex skill 形式的 PHP 版本检查工具,思路是把受影响版本范围做成技能,让 Codex 逐台核对各 SAPI 的版本,入口在 OpenAI 那篇博文的配套链接里,名称以官方页面为准。几百台机器的资产盘一遍,靠人敲命令确实熬不住。

图:OpenAI 配套开源的 PHP 版本自检工具仓库卡,随公告一同放出
协调披露是怎么跑完的
这次披露流程本身值得看一眼,规模罕见。
时间线(Sansec 整理,UTC):8 月 1 日 Calif 确认多条 RCE 路径;8 月 11 日向 PHP 报告,协调披露启动;8 月 24 日 Wiz Research 独立报告;10 月 20 日细节泄露,watchTowr 确认可 RCE;10 月 21 日 07:43 Cloudflare 报告早期攻击;14:00 PHP 发布修复版本,Calif、Wiz、OpenAI 同步发文。
细节泄露在补丁前一天,攻击观测在补丁前 6 小时。这个顺序基本堵死了"再缓几天"的空间。
分工是这样的:Patch the Planet 计划下,Calif 用 GPT-5.6 Sol 发现其中一个严重漏洞,Wiz 独立发现并报告了两个;PHP 维护者主导验证、修复和发版;OpenAI、Wiz、Cloudflare 提供研究、技术支持和跨机构协调。OpenAI 称这是近年来影响最大的安全问题之一,并且提了一个概念,防御者窗口期:据他们所知,前沿 AI 比攻击者更早发现了这些漏洞。
配套动作做到了政府层面。OpenAI 给出五阶段框架:验证并修复上游漏洞;给受影响组织留行动时间;与政府协调,联络了白宫超级智能工作组、ONCD、CISA 及国际伙伴;为各受影响产品准备更新;补丁发布后发指导并支持部署。荷兰动作最快,Tweakers、荷兰众议院、NCSC、Security.NL 在 10 月 21 日预防性下线。
AI 到底出了多少力
这是整个事件里我最想掰扯的部分。
OpenAI 的叙事是 AI 赢了攻击者一个身位。发现者 Calif 自己的 writeup 里有段很扫兴的话:"初始漏洞发现没有用特殊 harness,也没有用公众拿不到的模型。我聚焦在自己有背景、熟悉其漏洞历史的目标上。"后面还补了一刀:"没有一个模型能靠简单提示词挖出所有漏洞。至少现在没有。"
他还指出了 LLM 做变体分析的固有倾向:默认从最新、最著名的漏洞出发,向邻近代码扩展,不会主动从二十年前的冷门利用原语开始想。HN 上(id 50181175)有人据此质疑 OpenAI 把功劳过度归给 AI。
两种说法其实不冲突,拼起来才是完整图景。选目标、判断哪里值得挖,是人做的,Calif 对 PHP 内存漏洞史的积累是 2004 年那条线的延续;模型的贡献是那两个资源上限绕过的输入构造,属于组合搜索和体力活,恰好落在模型擅长的区间。"前沿 AI 比攻击者更早发现"没有说谎,只是省略了主语:是带着二十年领域知识的研究员指挥下的 AI 更早,这个定语省不得。
一条拖了 22 年的旧账
Calif 的 writeup 理了一条更长的线,比这次事件本身信息量还大。
2004 年,Stefan Esser 发现 PHP 首个 memory_limit 相关 RCE,当年他选择不公开 exploit,CORE 和 Immunity 手里都持有私有版本。2020 年,PHP bug #78876 报告了 OOM 之后临时文件未清理。2024 年,OSTIF 联合 Quarkslab 做审计,同一个 OOM 问题又被翻出来一次,因为"未证明可利用"没有修。
到 2026 年 7 月 30 日 OpenAI 邀请 Calif 加入 Patch the Planet,Esser 牵线 PHP 基金会维护者 Volker Dusch,8 月 1 日就出了结果。一个被审计机构发现过、被判定不构成威胁的问题,搁了两年,由一条新组装的协作链补上。
Patch the Planet 的主帖里还有别的数:Trail of Bits 在 19 个开源项目用 Codex 加 GPT-5.5-Cyber 找到数百个问题,包括 Linux kernel 的 8 个内核指针泄露 PoC 和 24 个本地提权 exploit,还有 OpenBSD 一处潜伏了 23 年的 System V 信号量 use-after-free。OpenAI 同时承诺通过 "Daybreak for Frontline Defenders" 提供价值 10 亿美元的使用补贴,给安全资源有限、承担关键服务的组织。
还没答案的问题
回头看,这次事件里技术反而是好理解的部分:内存安全老毛病,清理路径出岔,引擎层无解,升级是唯一正解。真正的变量在流程。22 年没人接手的旧账,8 月 11 日报给 PHP,10 月 21 日全球四个分支版本同步修复,中间还压着泄露和真实攻击。
Wiz 能独立找到这两个漏洞,攻击者那边有多少人也独立找到了?这次是 Cloudflare 先看到流量、官方抢在前面发补丁,窗口有 6 个小时。下一次窗口有多宽,没人说得准。
参考链接
- OpenAI:协调披露两项 PHP 严重漏洞的官方博文与五阶段响应框架 openai.com/index/coord...
- php.net:2026 年官方安全公告与 8.5.12/8.4.27/8.3.36/8.2.35 发布记录 www.php.net/archive/202...
- Calif:PHP2Shell 利用链技术 writeup 与发现过程自述 calif.io/php2shell/
- Sansec:PHP2Shell 研究报告、协调披露时间线与临时缓解配置 sansec.io/research/ph...
- IT之家:PHP 高危漏洞修复、OpenAI 牵头协调披露的报道 www.ithome.com/1/016/173.h...
- W3Techs:各服务端编程语言在网站中的使用率统计 w3techs.com/technologie...
- OpenAI:Patch the Planet 计划主帖,含 Trail of Bits 与 OpenBSD 案例数据 openai.com/index/patch...
- Hacker News:围绕本次披露与 AI 归功争议的讨论帖 news.ycombinator.com/item?id=501...