php2shell 漏洞:PHP 两个 9.2 分 RCE 应急加固指南
php2shell:PHP 爆出两个 9.2 分 RCE,附全版本应急加固工具包
2026-10-22 · 安全运维 · 阅读约 6 分钟
一句话结论:PHP 官方于 2026-10-21 紧急发布 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35,修复两个未授权远程代码执行漏洞。所有 PHP 5 以来的版本都受影响。临时配置只能降低暴露面,不能替代升级。(应急加固工具包见文末)
一、这是什么漏洞
这两个漏洞被社区合称为 php2shell,是 PHP 内核层面的问题,不是某个 CMS 或插件的问题:
| 编号 | 名称 | CVSS v4.0 | 原理 |
|---|---|---|---|
| CVE-2026-109618 | RCE via OOM corruption | 9.2 | 内存耗尽时 PHP 被打断,请求数据只初始化了一半,清理流程把无效数据当成了有效数据 |
| CVE-2026-109619 | RCE via stale global state | 9.2 | 请求的内部状态在其内存被释放后仍然存活,被同一个 worker 处理的下一个请求拿来用(UAF) |
三个让人头大的特点:
默认配置就能打。
session.upload_progress.enabled自 PHP 5.4 起默认开启,绝大多数人从来没关注过它。在业务代码执行之前就完成了利用,应用层的 WAF 和代码审计基本看不见。mod_php 风险最高,一个未授权请求即可触发。
不需要登录、不需要特定接口,成千上万次请求里成一次就能拿到 shell,适合自动化批量扫描。
二、影响范围
官方表述是:PHP 5 以来的每一个版本都受影响。只有下面四个分支拿到了修复版本:
| 分支 | 受影响区间 | 修复版本 | 状态 |
|---|---|---|---|
| 8.5.x | 8.5.0 ~ 8.5.11 | 8.5.12 | 受支持 |
| 8.4.x | 8.4.0 ~ 8.4.26 | 8.4.27 | 受支持 |
| 8.3.x | 8.3.0 ~ 8.3.35 | 8.3.36 | 受支持 |
| 8.2.x | 8.2.0 ~ 8.2.34 | 8.2.35 | 受支持(2026 年底 EOL) |
| 8.1 / 8.0 / 7.4 | 全系 | 无正式版本 | 仅有极简源码 backport |
| 7.3 及更早(含 5.x) | 全系 | 无 | 无补丁、无 backport |
受影响的 SAPI 包括 php-fpm、Apache mod_php、php-cgi、FrankenPHP、LiteSpeed。两个坑值得单独提醒:
EOL 分支的最后一个版本同样中招。比如 8.1.34、7.2.34、5.4.45,升到分支最后一版也没用。
版本号只能当初筛。Debian、Ubuntu、RHEL、Alpine 等常在不改 PHP 版本号的前提下回迁补丁,
php -v显示旧版本但二进制可能已修好,需要核对包变更日志。
三、临时止血方案(升级前的过渡)
官方明确说明:以下措施只是降低特定攻击路径的暴露面,不是修复。真正解决问题只有一条路——升级。
1. php-fpm pool 级配置(最关键)
; 粘贴进 pool 文件的 [www] 段内部,不要存成 pool.d 下的新文件 ; 必须用 php_admin_* —— 应用的 ini_set() 和 .user.ini 覆盖不了 php_admin_value[memory_limit] = -1 php_admin_value[post_max_size] = 8M ; 有上传业务改 32M php_admin_value[upload_max_filesize] = 2M ; 必须小于 post_max_size php_admin_value[max_file_uploads] = 20 php_admin_value[max_input_vars] = 1000 php_admin_value[max_input_nesting_level] = 32 php_admin_flag[session.upload_progress.enabled] = off php_admin_flag[display_errors] = off pm.max_requests = 500 ; 仅 PHP 8.5 才有这一行,其它分支写了会导致 php-fpm -t 失败 php_admin_flag[fatal_error_backtraces] = off
改完必须 php-fpm -t 校验,然后重启服务让所有 worker 重新加载配置(只 reload 主进程不够)。
2. Web 服务器与代理层
# nginx:请求体上界
client_max_body_size 8m;
client_header_buffer_size 4k;
large_client_header_buffers 4 8k;
# 不需要文件上传的站点,直接拒绝 multipart(最有效的一条)
map $http_content_type $block_multipart {
default 0;
"~*^multipart/form-data(?:\s*;|$)" 1;
}
if ($block_multipart) { return 403; }3. 三条反模式,别踩
不要用 RLIMIT_AS / RLIMIT_DATA 代替 cgroup:那会自己制造"有漏洞的分配失败",反而打开 CVE-2026-109618。应该用 systemd
MemoryMax做兜底。不要把 request_terminate_timeout / max_execution_time 调小当防护:那是在制造攻击者可触发的执行超时,官方缓解建议里点名要求"修掉"这类超时。
WAF 别只匹配单行干净的 PHP_SESSION_UPLOAD_PROGRESS:PHP 的 multipart 解析器接受折叠头、无冒号行、闭合引号后的垃圾字符,精确匹配会漏;而且这个字段名是可以改的。
4. 排查是否已经被打
ps -eo pid,ppid,args --forest | grep php # worker 下挂 sh/bash/nc/curl/python = 已失守 dmesg -T | grep -iE "segfault|general protection" | grep -i php grep -c "PHP_SESSION_UPLOAD_PROGRESS" /var/log/nginx/access.log grep -l "upload_progress" /var/lib/php/session/sess_* 2>/dev/null | head -20
四、php2shell 应急加固工具包
上面这些步骤散落在官方公告和各家分析里,落地时还要按自己的 PHP 分支做适配(哪些指令存在、哪些写了会让 FPM 起不来)。我把整套东西整理成了一个工具包:
包内文件(共 23 个)
php2shell-kit/
├── README.md 三步走用法 + 踩坑清单
├── 00-版本矩阵.md 分支区间 / 修复版本 / EOL / 覆盖性说明
├── 01-受影响版本全量清单.txt 538 个版本逐个列出,Ctrl+F 直接搜
├── 01-受影响版本全量清单.csv 可导入 Excel 做资产比对
├── 99-免责声明.txt
├── probe/
│ └── php2shell-probe.php 通用探针,PHP 5.0 ~ 8.5 全系可用
├── conf/
│ └── php-{8.5,8.4,8.3,8.2,8.1,8.0,7.4,7.3,7.2,7.1,7.0,5.6,5.5,5.4,5.3}.php-fpm.txt
└── scripts/
├── php2shell-audit.sh 只读自查:版本盘点 / 配置扫描 / IOC 排查
└── apply-php-fpm-hardening.sh 备份 + 幂等写入 pool + 语法校验几个值得单独说的设计:
15 份分支配置,不是复制粘贴。按各分支的指令可用性做了差异:
fatal_error_backtraces只出现在 8.5 那份(其它分支写了 FPM 直接起不来);session.upload_progress.*只在 5.4+ 出现;max_input_vars在 5.3.9 之前的分支自动剔除。538 个版本的全量穷举清单。不想理解区间就 Ctrl+F 搜自己的版本号,比如
8.4.11或7.2.9,直接看判定和处置目标。PHP 补丁版本号是连续整数、不跳号,所以区间可以无损展开成完整列表。一个探针跑遍 5.0 ~ 8.5。不用短数组语法、不用 PHP 8 的
ini_parse_quantity,新函数全部做了function_exists保护。通过 HTTP 访问才能拿到 mod_php / php-fpm 的真实生效值——CLI 的php -i经常是另一份配置。探针还会轻扫 session 目录,找出被塞进upload_progress的对象序列化残留(O:),那是被尝试利用的直接证据。写入脚本会自动备份、幂等、校验,但故意不自动重启——重启是整个操作里唯一会影响线上业务的一步,应该由人来决定时机。
获取下载地址:
php2shell 应急加固工具包(CVE-2026-109618-109619).zip
(25 个文件,93 KB)
五、最后
处置顺序建议是:今晚做缓解 → 明天升版本 → 顺手排查入侵迹象。对于 7.3 及更早的分支,缓解只是买时间,隔离 + 排期迁移才是正解——一台互联网可达的 EOL 分支 PHP,长期看是守不住的,这类机器上通常还并存着 CVE-2019-11043 之类的旧洞。
免责声明:临时加固操作无法保证堵住漏洞,仅为升级到最新版本争取时间,请尽快升级到最新版。本文及工具包内容基于 PHP 官方公告与公开资料整理,不构成任何形式的安全保证;修改生产环境配置前请务必备份,并以 php.net 官方公告与实际环境验证结果为准。
参考:php.net 安全公告(2026-10-21)· php.net/eol.php · php.net/supported-versions.php · NVD CVE-2019-11043
六、常见问题(FAQ)
php2shell 是什么漏洞?
php2shell 是 2026 年 10 月 PHP 官方紧急修复的两个内核级未授权远程代码执行漏洞的合称:CVE-2026-109618(RCE via OOM corruption,内存耗尽时请求数据半初始化、清理流程误用无效数据)与 CVE-2026-109619(RCE via stale global state,请求内部状态在内存释放后仍被下一请求复用,属 UAF)。两者 CVSS v4.0 均为 9.2,默认配置即可利用,且在应用代码执行之前完成利用。
我的 PHP 版本受影响吗?怎么快速自查?
官方口径是 PHP 5 以来的每一个版本都受影响。按分支判断:8.5.0~8.5.11、8.4.0~8.4.26、8.3.0~8.3.35、8.2.0~8.2.34 全部受影响,需分别升级到 8.5.12、8.4.27、8.3.36、8.2.35;8.1、8.0、7.4 无正式修复版本,仅有极简源码 backport;7.3 及更早(含 5.x)既无补丁也无 backport。可用 php -r 'echo version_compare(PHP_VERSION, "8.4.27", "<") ? "受影响" : "已修复";' 做初筛,或直接查 538 个版本的全量清单。注意 Debian、Ubuntu、RHEL、Alpine 常在不改版本号的情况下回迁补丁,版本号只当初筛,结论以包变更日志为准。
不升级 PHP,只改配置能防住 php2shell 吗?
不能。PHP 官方明确说明,关闭 session.upload_progress.enabled、设置 memory_limit=-1、降低 post_max_size、关闭 fatal_error_backtraces 等措施只是降低特定攻击路径的暴露面,不是修复。底层分配失败仍可能到达有漏洞的代码路径。唯一完整解法是升级到 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35。
php-fpm 应该改哪些配置做临时止血?
在 pool 文件的 [www] 段内部写入:php_admin_value[memory_limit] = -1、php_admin_value[post_max_size] = 8M(有上传业务改 32M)、upload_max_filesize = 2M(必须小于 post_max_size)、max_file_uploads = 20、max_input_vars = 1000、max_input_nesting_level = 32、php_admin_flag[session.upload_progress.enabled] = off、display_errors = off、pm.max_requests = 500。PHP 8.5 可再加 fatal_error_backtraces = off,其它分支写了会导致 php-fpm -t 失败。必须用 php_admin_* 而非 php_value,否则会被应用 ini_set() 覆盖;改完要校验并重启所有 worker。
为什么不能用 RLIMIT_AS 或 RLIMIT_DATA 代替 cgroup?
因为 RLIMIT_AS / RLIMIT_DATA 会主动制造分配失败,而 CVE-2026-109618 的触发条件之一正是内存分配失败,用它顶替 cgroup 等于自己打开漏洞路径。可用性兜底应使用容器或 cgroup 限制(如 systemd MemoryMax),并配置只杀掉受影响 worker 的策略。
PHP 5.4、7.2 这类已 EOL 的版本怎么办?
EOL 分支拿不到任何官方补丁,且分支最后一个版本同样中招(如 8.1.34、7.2.34、5.4.45),升到分支末版无效。可行做法只有:短期用 php-fpm 配置加 Web 服务器层限制做缓解,并把服务挪到 WAF 或内网之后;中期排期迁移到受支持分支(建议 8.3 及以上)。PHP 7.2 还需额外注意 CVE-2019-11043 这类并存的历史漏洞。
怎么判断服务器是否已经被利用?
排查四类迹象:一是 ps -eo pid,ppid,args --forest 看 php-fpm worker 下是否挂出 sh、bash、nc、curl、python 等子进程;二是 dmesg 中是否出现 php 相关 segfault 或 general protection(利用失败常直接段错误);三是访问日志中 PHP_SESSION_UPLOAD_PROGRESS 字段与 5xx 突增;四是 session 目录中是否存在同时含 upload_progress 与序列化对象标记 O: 的残留文件。
php2shell 应急加固工具包里有什么?
一个通用探针 php2shell-probe.php(PHP 5.0~8.5 全系可用,通过 HTTP 输出真实生效 ini 值并轻扫 session 目录残留);15 个 PHP 分支各自的 php-fpm 配置 txt;538 个受影响版本的全量清单(txt 与 csv 两种格式);以及只读自查脚本与带备份、幂等、语法校验但不自动重启的写入脚本。
处置的先后顺序应该怎么安排?
建议三步:当晚先在 php-fpm 与 Web 服务器层做临时缓解并重启 worker;次日尽快升级到官方修复版本并复查生效值;同时排查入侵迹象。对 7.3 及更早分支,缓解只是买时间,隔离加迁移才是正解。
文章网址:https://www.phprm.com/php/php2shell.html
随意转载^^但请附上教程地址。