PHP2Shell 修复 · 升级指南

如何修复 PHP2Shell

修复方法就是升级 PHP 再重启。任何配置修改、插件更新或 WAF 规则都替代不了它。这里有各常见平台的命令,以及如何证明补丁真的生效了。

最后核实 2026-10-22

目标版本

8.5.12、8.4.27、8.3.36、8.2.35 或更高——或者 changelog 中列出 CVE-2026-109618 和 CVE-2026-109619 的操作系统厂商软件包。PHP 8.1 及更早版本不会再有新版本——见下文。

分支存在漏洞修复版本
8.5< 8.5.128.5.12
8.4< 8.4.278.4.27
8.3< 8.3.368.3.36
8.2< 8.2.358.2.35
8.1 · 8.0 · 7.4全部仅源码回移植
5.4 – 7.3全部无修复

1. 找出所有 PHP 运行环境

遗漏的运行环境是整批服务器迟迟无法修复的最常见原因。请在每台主机上执行以下命令。

shell
# PHP processes running right now, and when they started
ps -eo pid,lstart,cmd | grep -E '[p]hp-fpm|[h]ttpd|[a]pache2|[f]rankenphp|[l]sphp'

# CLI and FPM can be different builds — check both
php -v
ls /usr/sbin/php-fpm* 2>/dev/null && for f in /usr/sbin/php-fpm*; do "$f" -v | head -1; done

# Is Apache running PHP in-process (mod_php)? That is the highest-risk setup.
apachectl -M 2>/dev/null | grep -i php

# PHP version inside every running container
docker ps --format '{{.Names}}' | while read c; do
  printf '%s: ' "$c"; docker exec "$c" php -r 'echo PHP_VERSION, PHP_EOL;' 2>/dev/null || echo 'no php'
done

另外别忘了检查镜像仓库里的基础镜像、CI runner、预发和预览环境、内置 PHP 的设备,以及没人管的老服务器。从外部看,curl -sI https://site | grep -i x-powered-by 有时能看到版本号,但大多数网站会隐藏它。 可用 NCSC-NL 产品清单 排查内置 PHP 的产品,再向各厂商确认修复状态。

2. 安装已修复版本

适用于系统自带软件包和 Ondřej Surý 的 PPA / packages.sury.org。Debian/Ubuntu 自带软件包会保留旧的上游版本号并回移植补丁,所以要以 changelog 检查结果为准。

shell
sudo apt update

# Upgrade only the PHP packages that are installed
sudo apt install --only-upgrade $(dpkg-query -W -f='${db:Status-Abbrev} ${binary:Package}\n' 'php*' | awk '$1=="ii"{print $2}')

# Proof the fix is in: the changelog should mention the CVE
# (replace 8.3 with your version)
apt changelog php8.3-common 2>/dev/null | grep -m1 -E 'CVE-2026-10961[89]' || echo 'NOT FIXED in this package yet'

3. 重启所有运行 PHP 的进程

安装软件包只会替换磁盘上的文件。正在运行的进程在重启之前,仍在执行旧的、有漏洞的代码。

shell
# Debian / Ubuntu (adjust the version)
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2        # if using mod_php

# RHEL family
sudo systemctl restart php-fpm httpd

# Anything still mapped to the old, deleted PHP binary needs a restart
sudo grep -l -E '(php|libphp)[^ ]* \(deleted\)' /proc/[0-9]*/maps 2>/dev/null
sudo needrestart -r l                 # Debian/Ubuntu helper, if installed

# Long-running PHP workers
php artisan queue:restart             # Laravel queues
php artisan octane:reload             # Octane (Swoole / RoadRunner / FrankenPHP)
sudo supervisorctl restart all        # supervisor-managed workers

4. 从 Web 服务器的视角验证

shell
# Version of the FPM binary that actually serves traffic
php-fpm8.3 -v 2>/dev/null || php-fpm -v

# Compare process start times with when you upgraded
ps -o pid,lstart,cmd -C php-fpm8.3,php-fpm,apache2,httpd

# Ask the web server itself (use a random name, delete straight after)
F="v-$(openssl rand -hex 8).php"
echo '<?php echo PHP_VERSION;' | sudo tee /var/www/html/$F >/dev/null
curl -s https://your-site.example/$F; echo
sudo rm /var/www/html/$F

打补丁后的新行为

补丁把内存耗尽时的中断改成在安全点检查的软限制,并新增一个更高的硬内存限制,一旦触及就用 _exit() 立即结束进程。触及硬限制时,关闭函数和析构函数都不会运行。如果你的应用在 register_shutdown_function 里做了工作(写日志、清理),升级后请测试内存消耗大的路径。

还在用 PHP 8.1、8.0、7.4 或更早版本?

这些分支已经停止支持,PHP 项目不会再为它们发布新版本,但鉴于漏洞的严重性,官方发布了最小化的源码回移植。

  1. 最佳方案:迁移到 PHP 8.4 或 8.5。如果时间紧,从 8.1 升到 8.3 跨度更小(8.2 将在 2026 年底结束支持)。
  2. 系统软件包:Ubuntu(含 Ubuntu Pro / ESM)、Debian LTS、RHEL 及其他长期支持厂商都提前拿到了补丁。按上文方法在软件包 changelog 中查找 CVE 编号。
  3. 自行编译:PHP 团队提供的回移植分支——PHP 8.1, PHP 8.0, PHP 7.4。它们只修复这两个 CVE,分支本身仍不受支持。
  4. 更早的分支:PHP 项目未列出低于上述范围的源码回移植,但发行商仍可能提供补丁:Ubuntu 已确认提供修复包,包括通过 Pro / ESM 支持的旧分支。确认补丁覆盖两个 CVE 并重启工作进程;若无已修复构建,应隔离主机并迁移。

5. 然后

  • 移除影响性能的临时缓解措施,比如 pm.max_requests = 1 或 memory_limit = -1,恢复合理的限制值。
  • 排查此前是否已被利用:入侵排查指南。打补丁不能撤销已经发生的入侵。
  • 在用 PHP 8.2?它的安全支持将于 2026-12-31 结束。趁现在升级流程还熟悉,尽快安排迁移到 8.4 或 8.5。

相关页面