PHP2Shell 是 PHP 本身的一对严重漏洞,编号为 CVE-2026-109618 和 CVE-2026-109619。这个 PHP 漏洞可能让未登录的攻击者在任何提供 PHP 页面的服务器上执行代码。修复方法是更新 PHP:升级到 8.5.12、8.4.27、8.3.36 或 8.2.35,或安装发行版提供的已修补软件包,然后重启所有 PHP worker。
漏洞细节于 10 月 20 日泄露,比原定的披露日期早了两天,PHP 项目随即在 10 月 21 日提前一天发布了修复版本。如果你运行任何基于 PHP 的系统(WordPress、WooCommerce、Drupal、Magento、Laravel、控制面板),今天就检查一下版本。
什么是 PHP2Shell 漏洞?
PHP2Shell 是研究人员给 PHP 运行时中两个远程代码执行漏洞起的名字,由 Calif、Wiz、OpenAI 和 Quarkslab 的研究人员报告。PHP 将两者都评为 CVSS v4.0 9.2 分。
| CVE | PHP 官方名称 | 问题出在哪里 |
|---|---|---|
| CVE-2026-109618 | RCE via OOM corruption(内存耗尽导致的损坏) | PHP 在初始化请求的过程中耗尽内存。随后的清理代码却信任了只构建了一半的数据。 |
| CVE-2026-109619 | RCE via stale global state(残留的全局状态) | 某个请求的内部状态比它指向的内存存活得更久。同一个 PHP worker 上的下一个请求可能会对这些残留数据进行操作。 |
漏洞出在 PHP 解析传入请求的环节,此时你的应用代码还没有开始运行。更新 WordPress、插件或框架对此没有任何作用,必须更换 PHP 二进制文件本身。
PHP 的安全公告点名了所有处理 Web 请求的运行方式:PHP-FPM、使用 mod_php 的 Apache、php-cgi、FrankenPHP 和 LiteSpeed。其中使用 mod_php 的 Apache 风险最高:已有演示的利用方式,只需一个未经身份验证的请求,就能在任何应用代码运行之前触发攻击。公告还提到,在 PHP-FPM 上,如果应用满足一定条件,也可以通过会话上传进度(session upload progress)功能实现远程代码执行。
哪些 PHP 版本受影响?
四个修复版本之前的所有版本。以下是 PHP 安全公告及其 10 月 21 日安全版本给出的信息:
| PHP 分支 | 修复版本 | 备注 |
|---|---|---|
| 8.5 | 8.5.12 | 积极支持 |
| 8.4 | 8.4.27 | 积极支持 |
| 8.3 | 8.3.36 | 仅提供安全修复 |
| 8.2 | 8.2.35 | 安全修复于 2026 年 12 月 31 日结束 |
| 8.1、8.0、7.4 | PHP 不再发布新版本 | PHP 发布了最小化源码补丁;发行版和 LTS 供应商提供自己的修复包 |
| 7.3 及更早 | PHP 不提供修复 | 升级,或选择仍在提供补丁的供应商 |
Cloudflare 和 Imperva 表示,这些漏洞最早可追溯到 PHP 5.4。PHP 公告把修复版本之前的所有版本都列为受影响,但没有指明最早受影响的版本。
版本号看起来很旧,也可能已经修补。 Linux 发行版会回移植修复,同时保留原来的上游版本号。Ubuntu 24.04 的修复包是 8.3.6-0ubuntu0.24.04.13,它报告的版本仍然是 8.3.6。Debian 12 为 8.2.35-1~deb12u1(DLA-4848-1),Debian 13 为 8.4.27-1~deb13u1(DSA-6574-1)。请拿完整的软件包版本去对照发行版的安全跟踪页面,而不是只看前三个数字。
PHP2Shell 是否已经被利用?
各方报告并不一致,而且每小时都在变化。按时间顺序,各来源的说法如下:
- 10 月 17 日: Amazon Threat Intelligence 在其 MadPot 蜜罐上记录到一次 PHP2Shell 利用尝试,比补丁发布早四天。该请求来自一个与商业匿名化服务相关联的 IP 地址。
- 10 月 20 日: 漏洞细节在网上泄露。watchTowr 确认漏洞属实。Huntress 表示尚未发现利用行为,也不知道有公开的利用代码。
- 10 月 21 日 03:02 UTC: Cloudflare 启用了针对 PHP2Shell 的 WAF 规则。它随后写道,观察到了针对其客户的攻击流量,攻击者还在修改 payload 以绕过规则。
- 10 月 21 日 14:00 UTC: PHP 发布修复版本。watchTowr 同一天报告,其蜜罐网络上出现了针对这两个漏洞的利用。
- 10 月 21 日下午(美国时间): PHP 基金会执行董事对 CNBC 表示,没有证据显示存在可用的利用代码,只有“不完整、方向错误、无法运行的生成代码”。Imperva 报告称,在其披露前的监测中没有发现匹配的流量。
- 10 月 23 日: 两个 CVE 都还没有列入 CISA 的已知被利用漏洞(KEV)目录(该目录最近一次更新是 10 月 21 日)。
研究人员已经做出了可用的利用代码,其他团队也表示复现了这些漏洞。请假定攻击者同样做得到,把每一台未打补丁、面向互联网的 PHP 服务器都视为已暴露。
如何检查 PHP 版本
要检查的是处理 Web 请求的那个 PHP。在许多服务器上,命令行 PHP 和网站背后的 PHP 并不是同一个构建。
在服务器上:
php -v # command line PHP
php-fpm8.3 -v # the FPM build (the name varies: php-fpm, php-fpm8.4)
apachectl -M | grep php # a php_module line means Apache runs PHP as mod_php
dpkg -l | grep php # Debian/Ubuntu: the full package versions
rpm -qa | grep php # RHEL, Rocky, Alma, Fedora
在浏览器中: 在网站根目录放一个名为 info.php 的文件,内容为 <?php phpinfo();,打开它,查看顶部的版本号和 Server API 一行(它会告诉你是 FPM、Apache 2.0 Handler 还是 CGI)。看完立即删除该文件,因为它会暴露你的全部配置。
在 WordPress 中: 进入工具 > 站点健康 > 信息,展开服务器。其中的 PHP 版本一行就是你的网站实际运行的版本。
在主机控制面板中: cPanel 在 MultiPHP Manager 或 Select PHP Version 中显示,Plesk 在域名的 PHP 设置中显示,大多数托管主机则显示在网站概览页上。
在 Docker 中: docker exec <container> php -v 会报告正在运行的容器里的 PHP,这才是真正起作用的那个。
如果想从外部测试,据 Help Net Security 报道,Searchlight Cyber 发布了开源检测工具 php2shell-scanner。只对你自己拥有的主机运行它。
如何修补 PHP2Shell
对所有技术栈都适用的顺序:先处理面向互联网的服务器,然后重启所有 PHP 进程。只要旧的 worker 还在处理请求,磁盘上已修补的二进制文件就不起任何作用。
Debian 和 Ubuntu
sudo apt update && sudo apt upgrade
sudo systemctl restart php8.3-fpm # match your version
sudo systemctl restart apache2 # if you use mod_php
然后用 dpkg -l | grep php 查看软件包版本,并对照 Debian 或 Ubuntu 的安全跟踪页面。在 Ubuntu 20.04 及更早版本上,修复后的 7.x 软件包通过 Ubuntu Pro 提供。第三方软件源按自己的节奏更新:Help Net Security 报道称,rpms.remirepo.net 在发布当天还没有更新,所以在依赖它之前,先确认你用的源已经发布了修复。
RHEL、Rocky、AlmaLinux 和 Fedora
运行 sudo dnf upgrade 'php*',然后重启 php-fpm 和 httpd。修复后的软件包版本请查看供应商的安全公告,因为它和上游版本号对不上。
Docker 镜像
Docker Hub 上的官方 php 镜像已于 10 月 21 日推出 8.5.12、8.4.27、8.3.36 和 8.2.35 标签。固定其中一个标签,重新构建并重新部署:
FROM php:8.4.27-fpm
docker compose build --pull && docker compose up -d
正在运行的容器在被替换之前会一直使用旧的 PHP。基于 php 构建的镜像(包括 wordpress)同样需要重新拉取并重新部署。
共享主机(虚拟主机)和 cPanel
这种环境下你无法自己修补 PHP。主机商会更新控制面板提供的 PHP 构建(大多数 cPanel 服务器上是 EasyApache 的 ea-php 或 CloudLinux 的 alt-php)。查看主机商的状态页面,或询问客服,确认他们的 PHP 构建是否已包含 CVE-2026-109618 和 CVE-2026-109619 的修复。如果你的网站仍在运行 7.4 或 8.1,请在 MultiPHP Manager 或 Select PHP Version 中切换到 8.3 或更高版本;如果有测试副本,先在测试副本上验证。
WordPress 托管主机
主机商会替你修补 PHP。WordPress.org 表示,这些漏洞不需要也不打算发布 WordPress 更新。确认主机商已推出修复,然后查看站点健康 > 信息 > 服务器。如果网站运行在 PHP 8.1 或更早版本上,请升级,因为这些分支只能拿到供应商的回移植补丁。
Windows 和源码构建
修复后的源码和 Windows 二进制文件可以在 php.net 下载页面获取。对于 7.4、8.0 和 8.1,PHP 为自行构建 PHP 的用户发布了最小化源码补丁。
如果今天无法打补丁
PHP 在这一点上说得很直白:只有更新才是完整的修复。它的公告列出了一些设置,可以阻断特定的攻击路径,但不能让服务器真正安全:
- 在
php.ini、FPM pool 或服务器配置中设置session.upload_progress.enabled=0(不要用ini_set()或.user.ini),然后重启所有 worker。这可以阻断已确认的会话攻击路径。 - 在 PHP 8.5 上,设置
fatal_error_backtraces=0并重启所有 worker。 - 用应用无法覆盖的方式设置
memory_limit=-1,例如php_admin_value。同时配合较低的post_max_size(不接收上传时 8M,接收上传时 32M),以及容器或 cgroup 内存限制。不要使用RLIMIT_AS或RLIMIT_DATA,它们可能触发漏洞。 - 在 Web 服务器或代理层限制请求大小、字段数量、multipart 分段数量和嵌套深度;如果网站从不接收上传,直接拦截 multipart 请求。
每项更改在推广前都要先测试,因为有些设置会让上传失效。如果某台服务器无法及时修补或缓解,英国 NCSC 和 WordPress.org 都建议考虑把它下线,或者放到 VPN 或允许列表之后,只让已知地址访问。
打补丁期间如何减少暴露面
以上措施都挡不住扫描器发来的请求。针对新漏洞的大规模利用是自动化的:脚本扫遍整个互联网寻找 PHP 服务器,再对每一台发起攻击。这些扫描器通常运行在托管和数据中心网络里租用的服务器上,或者经由 VPN、代理和 Tor 转发。Amazon 首次发现的那次尝试就来自一个匿名化服务。而真实访客很少从数据中心访问网站。
所以在你修补所有服务器的这几天里,可以多加一道防线:在请求到达 PHP 之前,拒绝来自这些网络的请求。IPScanner 不会检测 PHP2Shell,也不会修复 PHP。它检查的是谁在连接,把每个访客归入一个类别(真人、已验证爬虫、恶意自动化、托管、Tor、VPN、代理等),然后拦截你选择的类别。
检查必须在 PHP 前面运行。PHP2Shell 在 PHP 解析请求时就会触发,所以任何在 PHP 内部运行的东西都来不及。
| 你的部署 | 检查在哪里运行 | 指南 |
|---|---|---|
| 网站在 Cloudflare 后面 | Cloudflare Worker,在 Cloudflare 把请求转发到源站之前 | Cloudflare Worker |
| PHP 前面是 Traefik | Traefik 插件,在请求到达容器之前 | Traefik 插件 |
| PHP-FPM 前面是 Caddy | Caddy 模块,在 php_fastcgi 之前 | Caddy 模块 |
| PHP-FPM 前面是 nginx | 通过 auth_request 的 forward-auth 网关,在 fastcgi_pass 之前 | nginx 网关 |
| 只有 WordPress 或 WooCommerce | 插件在 PHP 内部运行,所以无法阻止这种攻击 | WordPress 插件 |
WordPress 插件和 WooCommerce 检查可以在表单处挡住虚假注册、垃圾内容和盗卡测试,但对 PHP2Shell 来说,它们处在错误的层级。如果一个 WordPress 网站跑在单台 Apache 服务器上、前面什么都没有,最快的办法是在它前面加上 Cloudflare 和 Worker。
查询访问日志中的 IP
先用监控模式,再开启拦截。 监控模式会记录每一个判定结果,但不拦截任何请求,这样你在改动任何设置之前,就能看清是谁在访问你的 PHP 端点。几个小时后,把托管、Tor 和恶意自动化设为拦截。VPN 和代理要看情况:在管理后台上可以拦截,在面向公众的商店上则要三思。来自爬虫目录的已验证搜索引擎和 AI 爬虫始终放行。
拦截功能需要 Starter 套餐。在 Free 套餐上,网站只能以监控模式运行。新账户可以使用七天的 Starter 功能,无需信用卡,足够覆盖一个补丁窗口期。详见价格。
这些限制要心里有数:
- 攻击者如果用的是家庭宽带,或者检测没有识别出的住宅代理,请求仍然会到达 PHP。
- 网关采用故障放行(fail open)。如果 IPScanner API 响应缓慢或无法访问,请求会直接通过,网站保持在线。
- 流量必须经过网关,网关才有用。如果你的源站在公网 IP 上直接响应,扫描器会完全绕过 Cloudflare,所以要让源站只接受来自 Cloudflare IP 段的连接。
如果你的网站使用 Cloudflare,也请保持它的托管 WAF 规则开启。Cloudflare 表示,自 10 月 21 日起,其 PHP2Shell 规则已在所有套餐上默认运行。这些规则检查的是请求本身,IPScanner 检查的是发出请求的是谁。两者都不能代替补丁。
检查服务器是否已被入侵
如果某台服务器从 10 月中旬起一直未打补丁并暴露在外,在继续下一步之前先排查一下。安全公告和事件响应人员指出的迹象是一致的:
- 发往
.php路径的大型或深度嵌套的 multipart POST 请求,请求体中常常带有PHP_SESSION_UPLOAD_PROGRESS - 错误日志中出现 "Allowed memory size exhausted" 错误,以及成批崩溃或被重新拉起的 PHP worker
- 网站根目录中出现新增或被修改的文件,或者新增的 cron 任务、用户账户
- PHP 或 Web 服务器进程启动 shell,或者建立你不认识的对外连接
如果怀疑已被入侵,在重启任何东西之前,先隔离服务器并保留日志,然后轮换 PHP 能读取到的所有密钥:数据库密码、API 密钥、会话密钥。
PHP2Shell 检查清单
- 列出你运行的所有 PHP,先列面向互联网的,包括控制面板、网络设备和容器。
- 找出处理 Web 请求的那个版本(phpinfo、站点健康、
php-fpm -v),而不仅仅是php -v。 - 安装 8.5.12、8.4.27、8.3.36、8.2.35 或发行版的修复软件包。
- 重启所有 PHP-FPM pool、Apache 和 LiteSpeed worker;重新构建并重新部署容器。
- 如果是 8.1 或更早版本,获取供应商的回移植补丁或者升级;两者都做不到时,把网站下线或只允许名单内的地址访问。
- 暂时无法打补丁?应用 PHP 给出的临时设置,并限制访问。
- 在 PHP 前面加一道网关(Cloudflare、Traefik、Caddy、nginx),先监控,再拦截托管、Tor 和恶意自动化。
- 让源站只接受它前面那层代理的连接。
- 从 10 月 17 日起搜索日志,查找上面列出的迹象。
- 在任何曾经暴露且未打补丁的服务器上轮换密钥。
来源:PHP 安全公告、GHSA-w8hw-w9fx-j79w、GHSA-6wmf-4rv5-p3rp、WordPress.org、Cloudflare、watchTowr FAQ、watchTowr、Help Net Security、SecurityWeek、The Hacker News、CNBC、Imperva、Qualys、Armis、Ubuntu、Debian。
常见问题