ARTICLE · 1233173
AI 让一个存了 20 年的 PHP 漏洞,变成了能打的漏洞
第一个要命的地方是位置。洞在 PHP 的核心引擎里,不在你的业务代码里。官方信息站写得很直接,一个只有 Hello World 的应用,跑在受影响的 PHP 版本上,一样中招。
第二个要命的地方是默认配置。Apache 配 mod_php 的情况下,一个未登录请求就能在任何应用代码运行之前触发,官方确认默认配置下可以做到完整的远程代码执行。
第三个是范围。PHP 支撑全球约 70% 的网站,WordPress、Drupal、Joomla、维基百科背后的 MediaWiki 全在里面。第三方安全机构 TechTarget 的估算是有 2200 万台暴露服务器面临风险。这个洞的 PoC 在公开当天就有人放了出来,三个仓库累计三千多星,也就是说这事已经不是理论风险了。
研究方在真实容器镜像上验证过的应用清单很长。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。列这些名字就一个目的,说明洞在引擎里,你的框架再新也挡不住。
两个洞的机理说人话。第一个是内存耗尽的时候,PHP 可能留下一半没初始化完的内部数据,后面又把它当成有效数据用,等于自己把内存搞脏了。第二个是致命错误发生在错误的时点,留下的状态指向了上一个请求的内存,同一个 worker 处理下一个请求时就用到了那块已经释放的内存。两个都长在 PHP 几乎每个请求都会碰到的地方,内存管理和错误处理。
补丁的规模能说明问题,Zend 引擎改了 300 个文件。
下面五步,按顺序做。
版本对照,低于修复版的就是受影响。
四条查法,按可靠性排。命令行跑 php -v 看版本号。用官方那个检查工具,openai/php2shell-checker,能查 URL 也能查本地二进制。用包管理器,apt list --installed | grep php 或者 brew list --versions php。看容器镜像的 tag。
官方那个检查工具有四条限制,不说清楚会给你假的安全感。它只读 HTTP 响应头里的 X-Powered-By 和 Server,或者本地 php -v 的输出。它不跟随重定向,不看响应体。头部被隐藏或改写的时候它返回 UNKNOWN,而 UNKNOWN 不等于安全。它给的 OK 也只是版本号比大小的结论,本身不验证补丁是不是真的生效了。
还有个时间点要提醒。PHP 8.2 的官方支持在 2026 年 12 月 31 日结束,也就是这个分支打完这最后一个安全补丁,两个月后就彻底不修了。还在 8.2 上的项目,这次升完得顺手排一下升级计划。
重启这一条很多人会漏。只换文件不重启,旧进程还在跑旧代码,等于没修。官方明确要求重启 Apache、PHP-FPM 以及任何长驻的 PHP worker 进程。
不同运行方式的风险不一样,对运维有用。
一句话,跑 mod_php 的最危险,跑 FPM 的相对好一些但不是免疫。
前提先说死。官方原话是不存在完整的缓解措施,升级是唯一安全的选择。下面这些手段只能拖时间,不能替代补丁。
针对内存耗尽那一条,可以用 php_admin_value 把 memory_limit 设成 -1,让它永远不触顶。但代价是失去内存保护,恶意请求可能直接把你的进程打到内存耗尽。同理还要压低 post_max_size,不上传文件的环境设 8M,要上传的设 32M,并且保证 upload_max_filesize 小于它。在 Web 服务器或反向代理那一层限制解码后的请求大小、字段数量、multipart part 数量、header 数量和嵌套深度。用容器或 cgroup 限制内存。不要用 RLIMIT_AS 或 RLIMIT_DATA 去限。
针对跨请求残留状态那一条,把 session.upload_progress.enabled 设成 0,并且重启所有 worker,因为运行时用 ini_set 或 .user.ini 改是不生效的。8.5 上再设 fatal_error_backtraces=0。顺手清掉那些无效或已废弃的 per-request 设置,它们会额外制造致命错误点。最后一条最容易漏,把攻击者能触发的致命错误和执行超时都修掉。
社区已经把检测规则开源了,四套覆盖主流工具链。Suricata 和 Snort 有 13 条,包含请求、响应、侦察三类。Sigma 有 5 条,覆盖 Web 日志、进程创建、文件事件。ModSecurity v2 和 v3 有 7 条,Apache 和 Nginx 可以直接挂。还有一个 OpenResty 的 Lua 模块,适合放在反向代理层。
最省事的一条临时拦截,是在 multipart POST body 里挡掉 PHP_SESSION_UPLOAD_PROGRESS。正常业务几乎不用这个字段,副作用很小,但它盖住了两个漏洞的主要入口。
这不是局部事件。日本 IPA 在 10 月 22 日发了公告,斯洛文尼亚 SI-CERT、阿尔巴尼亚 AKSK 都发了预警,国内也有安全厂商在发通告。华尔街日报和纽约时报都写了。
这一段最容易被忽略。这个洞除了远程执行代码,还有内存泄露。官方说法是可能读到其他请求或者服务器自身的密码、登录令牌、API key 还有证书。
也就是说,一台暴露在公网、跑过受影响版本的机器,即使你没发现异常,也该假设凭据可能已经被读走了。补完洞之后应该按这个假设做轮换,数据库密码、API key、证书、会话密钥,一个都别省。
到这里是「该做什么」。下面说「为什么这件事值得你多想五分钟」。
它不是新出现的。2020 年就有人报过相关线索,编号是 PHP 的 bug #78876,描述是某些长变量会导致内存耗尽、临时文件没有被清理。当时没多少人当回事。
2024 年,事情曾经走到过一个很接近的节点。PHP 基金会用 Sovereign Tech Agency 的资金,通过 OSTIF 组织了 PHP 多年来第一次外部安全审计,执行方是 Quarkslab。一次正经的、有资金支持的、由外部机构执行的审计,在 PHP 这个量级的项目上并不多见。那次审计重新发现了同一个内存耗尽的问题。
结果是,因为无法证明它可利用,这个 bug 没有被修复。
这次的研究方是在看一个旧补丁时撞见这条线索的。那个 2020 年的补丁在 git 里还带着 security-audit-2024 的标签,等于把两年前的判断过程留在了代码历史里。
这一段值得停一下。一个可以在正式审计里被「证明不了能打」而搁置的问题,两年后变成了现实威胁。「无法证明可利用」曾经是一个可以接受的风险处置理由。这个理由现在失效了。
现在的流行说法是「AI 发现了 PHP 的严重漏洞」。这个说法既高估了 AI,也低估了人。
真实的分工是这样的。发现方是 Wiz Research 的四个人,加上 OpenAI Codex Security 的 Amy Burnett,加上 Calif 的 Ryan Austin。催化这件事的是 OpenAI 的 Patch the Planet 计划,7 月 30 日把 Calif 拉了进来,PHP 基金会的 Volker Dusch 负责牵线。
Wiz 官方博客有一句话,是整件事最准确的表述。翻译过来是,这些底层缺陷已经存在了几十年,但要证明它们可利用,需要一条极其复杂的攻击链,接近人类研究者实际能达到的上限。前沿 AI 模型大幅降低了这个门槛,把一个长期存在的缺陷变成了可用的漏洞利用。
注意这句话的重心。Wiz 说的不是「AI 找到了漏洞」,说的是「AI 降低了证明可利用的门槛」。
而 Austin 在自己的技术报告里还专门泼了一盆冷水,这一节叫「我们是怎么找到这个的」。他说初始发现没有用任何特殊工具,也没有用普通人拿不到的模型。他选了一个自己有背景、熟悉漏洞历史、并且带着明确假设的方向。他原话的意思很直接,没有哪个模型能靠一句提示词挖出所有 bug,至少现在还没有。
他还提到 LLM 的一个行为特征,特别值得记。模型的默认变体分析会倾向于从最新、最显眼的 bug 往邻近的旧代码走,不会自觉地回到二十年前的冷门利用原语。所以研究者自己脑子里那张「目标的漏洞历史图」依然关键,它决定了你能把模型往哪个方向推。
还有一个技术细节,我觉得是这件事里最值钱的部分。Austin 在发现第一个洞之后,让模型把失败模式泛化成了一个技能文件,写的是这样一条链,发布或销毁状态,执行可能失败的操作,然后初始化或提交或恢复;如果失败的操作里发生了非局部致命错误,提交就被跳过,下游的消费者于是相信了那个错误状态。这个技能文件后来带来了第二个更严重的发现。
所以准确的说法分三段。漏洞的存在,2024 年的审计就看见了。漏洞的可利用性,人类团队当时证明不了,所以没修。2026 年,人给方向,AI 给耐心,把「证明不了」推进成了「有可用的 PoC」。AI 在这里真正做的事,是把一个洞变成了一类洞。
你依赖的开源基础设施里,可能躺着一批「已知但证明不了」的洞。过去它们被归到低优先级,理由是没有证据表明能打。现在这个分类标准不稳了。
PHP 基金会在公告里还说了一件事,他们正在加强 PHP 的安全建设,包括把生态安全团队做实、把漏洞报告流程理顺。一个开源基础设施被打疼一次之后怎么调整自己,这部分通常不会上新闻,但它决定了下一个洞还会不会在代码里躺十几年。
攻方的成本在降,守方的审计成本也在降。这是一场不对称的军备竞赛,但至少这一轮,白帽跑在了前面。从 8 月 11 日上报到 10 月 21 日补丁上线,只用了两个多月。社区同步出了四套检测规则,OpenAI 还写了检查工具,12 家厂商在同一天发公告。
这一轮防守方赢了。发现方是白帽,走的是协调披露,PHP 团队响应极快。Wiz 的公告里还专门感谢了 PHP 团队的反应速度和专业程度。
但同一套能力,攻守两边都拿到了。下一次,先动手的未必是白帽。
现在你能做的只有两件事。查版本,打补丁,重启。以及从今天起,别再拿「证明不了它能被打」当作不修的理由。
💬 互动话题
你手上还有跑着旧版本 PHP 的机器吗?这次的补丁你敢直接上生产,还是先灰度?评论区聊聊你们的应急流程。
👍 如果觉得有用
欢迎点赞、收藏、转发三连。
我是Hank, 我们下次再见。















































































