发生了什么
10 月 21 日,PHP 项目发布了两个漏洞的修复:CVE-2026-109618 和 CVE-2026-109619。两者的 CVSS 评分均为 9.2,根据 Arctic Wolf 的分析文章,它们可以让未经身份验证的攻击者在用 PHP 处理 Web 请求的服务器上执行代码。
这些漏洞存在于 PHP 自身的请求处理生命周期中,而不是某个框架或插件里:
- CVE-2026-109618 是一个内存损坏漏洞,当请求数据只完成部分初始化时,内存不足状况中断 PHP 就会触发它。
- CVE-2026-109619 是一个释放后使用(use-after-free)漏洞:属于某个请求的状态可能残留下来,被同一 worker 上后续的请求读取,还可能泄露内存内容。
第二点值得停下来想一想。Qualys 指出,泄露的 worker 内存中可能包含密码、令牌和 API 密钥。所以即使没人在你的服务器上拿到 shell,机密信息也可能被带走。
补丁发布后事态发展迅速,规模也很大:The Hacker News 引用 Censys 的估算,仍有超过 3200 万个 PHP 服务运行着受影响的版本。
- 据 BleepingComputer 报道,Amazon 的威胁情报团队表示,针对性攻击在修复发布前四天就已开始。
- 10 月 24 日,Perplexity 的一名研究人员确认在蜜罐上成功实现了代码执行(The Hacker News)。
- 10 月 26 日,CISA 将这两个 CVE 加入其已知被利用漏洞(KEV)目录,并要求美国联邦机构在 10 月 29 日前完成修复。
为什么这对小型应用也很重要
攻击者在这里不会按公司规模挑选目标。他们扫描整个互联网,寻找任何像 PHP 一样响应的服务,然后尝试利用漏洞。VPS 上一个被遗忘的副业项目和大型电商网站一样容易被攻击到。
有几个细节让这次漏洞特别值得立即处理:
- 它与你的代码无关。Arctic Wolf 指出,由于漏洞位于 PHP 的请求处理中,是否暴露并不取决于你运行的是哪个应用。一个写得完美的 Laravel 应用,跑在旧的 PHP 版本上依然会暴露。
- 很多服务器配置都在影响范围内。Apache 搭配 mod_php 被认为风险最高,但 PHP-FPM、php-cgi、FrankenPHP 和 LiteSpeed 也都被列为受影响,捆绑 PHP 的产品和设备同样如此。
- 旧版 PHP 很常见。Qualys 报告称,在它能识别版本的 PHP 安装中,约 71% 已经停止支持(EOL)。如果你用的是 8.1 或更旧的版本,上游不会再为你提供常规修复。
如何检查你的应用
每台服务器你只需要一个答案:是否有东西在用 PHP 处理 Web 请求,具体是哪个版本?
1. 列出你托管的所有东西。不只是主应用,还包括营销网站、博客、文档、预发布环境、管理工具以及任何子域名上的东西。被遗忘的那些才是最危险的。
2. 查看响应头。很多 PHP 配置会在 X-Powered-By 或 Server 头中自报家门。没有这个头并不代表没有 PHP(可以用 expose_php = Off 关闭),但有这个头就能快速确认。详细的错误页面是另一个破绽:生产环境中的 PHP 堆栈跟踪会准确告诉攻击者你在运行什么。
curl -sI https://your-site.example | grep -i -E 'x-powered-by|server'
# X-Powered-By: PHP/8.3.20 <- PHP, and an old patch level详细错误页面和堆栈跟踪:如何关闭它们3. 检查实际处理 Web 流量的版本,而不只是 CLI。服务器上的 php -v 报告的版本可能与 Apache 或 PHP-FPM 实际使用的不同;Qualys 特别指出了这一点。检查 FPM 二进制文件或 Web 服务器的 PHP 模块,或者询问你的托管商。
php-fpm8.3 -v # or php-fpm -v, depending on your distro
apache2ctl -M | grep php # is mod_php loaded?4. 与已修复的版本进行比较。如果你通过 Linux 发行版安装 PHP,修复可能已被回移植到版本号看起来较旧的软件包中,所以请查看发行版的安全公告,而不是只看版本号。否则,你至少需要:
- PHP 8.5:8.5.12
- PHP 8.4:8.4.27
- PHP 8.3:8.3.36
- PHP 8.2:8.2.35
5. 使用托管服务?如果你用的是托管 WordPress 主机或 PaaS,请查看他们的状态页或更新日志,看有没有关于 PHP2Shell 的通知。大多数会替你打补丁,但“大多数”不等于“全部”,而自己管理的 VPS 则完全要靠你自己。
如何修复
先打补丁,再重启。更新 PHP 是唯一完整的修复方法。
重启很重要:运行中的 worker 在被替换之前会一直把旧代码保留在内存中。如果用 Docker,请基于更新后的基础镜像(例如当前的 php:8.3-fpm 标签)重新构建并重新部署。不要只是重启旧容器。
在使用 PHP-FPM 的 Debian 或 Ubuntu 上,通常类似这样:
sudo apt update && sudo apt install --only-upgrade 'php8.3*'
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2 # if you use mod_php如果今天无法打补丁,Qualys 总结了 PHP 官方的临时缓解措施。它们能降低风险,但不能让未打补丁的服务器变得安全。请在 php.ini 或 FPM 池配置中设置(不要用 .user.ini 或 ini_set),然后重启所有 worker。
如果某个服务尚未打补丁且不需要公开访问,请把它放到 VPN 或 IP 白名单之后,或者在能更新之前先下线。
; php.ini or FPM pool config (not .user.ini or ini_set)
session.upload_progress.enabled = 0
post_max_size = 8M ; 32M if you need uploads
upload_max_filesize = 6M ; keep below post_max_size如果你用的是 PHP 8.1 或更旧的版本,现在就规划升级。部分旧分支有有限的回移植修复,但每次出现这类漏洞时,你都只能靠运气。
查找入侵迹象。检查是否有异常进程、Web 根目录中的新文件、陌生的 cron 任务以及从 Web 服务器发出的外连。Arctic Wolf 还指出,日志中许多“PHP2Shell”请求复用的是较旧的技术,所以一条看起来吓人的日志并不一定意味着入侵成功。
如果曾经暴露,请轮换机密。由于 CVE-2026-109619 可能泄露 worker 内存,凡是经过未打补丁、面向互联网的 PHP 进程的机密,都应视为可能已被看到。这包括数据库密码、API 密钥、会话签名密钥和支付服务商密钥。Laravel 等框架把这些保存在 .env 中,所以还要确认这个文件从来没有能通过 Web 访问。
快速检查清单
对你拥有的每个域名逐项检查:
- 你拥有的每个域名和子域名都已列出,包括旧的营销网站和预发布网站。
- 你知道哪些运行 PHP,以及实际处理 Web 请求的确切版本。
- 每一个都已升级到 8.5.12、8.4.27、8.3.36、8.2.35 或厂商已修补的版本。
- 更新后已重启 PHP worker 和 Web 服务器。
- 任何尚未打补丁的服务都已限制访问或下线,并应用了缓解措施。
- 暴露主机上的机密已经轮换。
- 生产环境不再公开 PHP 版本,也不再显示堆栈跟踪。
更大的教训
PHP2Shell 会在几周内被修补并被遗忘,但这种模式不会。从“修复发布”到“被利用”的间隔如今只有几天,有时甚至是负数。小团队靠英雄主义是跑不赢的。真正有效的是清楚自己在运行什么,并在其中有东西发生变化时迅速察觉。
这和我们的 AI 应用上线检查清单背后的思路一样:现实中的大多数安全事件都源于容易检查的问题——前提是你真的去检查。
AppSafe 从外部扫描你的线上网站,就像攻击者看到的那样。它会查找缺失的安全头、泄露技术栈的 X-Powered-By 头、暴露的文件和详细错误等问题,并给出通俗易懂的修复方法。打完补丁后,对你的每个域名运行一次免费扫描,顺手把其他容易解决的问题也一并处理掉。
