PHP2Shell(CVE-2026-109618 / CVE-2026-109619)——配置层缓解方案

适用场景:不改二进制、不重编译 ,只靠运行期配置争取时间。

结论先行:配置层能显著降低可利用性,但官方核心开发者明确说过------单独关 upload_progress 不够 。配置是"止血",真正的"根治"在自编译篇(应用官方补丁)。

核实依据:php-src 发版 tag php-8.2.35 / 8.3.36 / 8.4.27 / 8.5.12;7.x 与 ≤8.1 无发版 tag。


1. 漏洞是什么(一句话根因)

请求处理中触发致命错误(典型是超 memory_limit 的 OOM),PHP 用 zend_bailout()(longjmp)直接跳出,native 清理被打断,全局状态只清了一半。随后:

  • CVE-2026-109618 :session.upload_progress 回调在半清理状态下,把 worker 的已释放内存 通过 PHPSESSID 回显给客户端------即使应用从不调用 session_start() 也会触发(内存泄露,类 Heartbleed)。
  • CVE-2026-109619 :致命错误的 backtrace 处理 + OPcache 类型混淆,在 worker 复用时读到上一个请求的残留状态 → RCE。

两条已知利用链的共同前提 :接受 multipart/form-data 请求、session.upload_progress.enabled=On(出厂默认开)、同一 worker 连续处理多个请求。


2. 通用缓解动作(5.x / 7.x / 8.x 都适用)

动作 作用 代价 覆盖哪条
session.upload_progress.enabled = 0 关掉 upload_progress 回调 极小(极少业务用 PHP 原生上传进度) 109618(部分)
pm.max_requests = 1 每个 worker 处理完一个请求即退出,打断"同一 worker 复用" CPU/fork 开销明显上升 109619(关键)
代理层对不需要上传 的接口拒绝 multipart/form-data 砍掉已知触发入口 需梳理哪些接口真的要上传 两条
memory_limit = -1,且不要用 RLIMIT_AS/RLIMIT_DATA 不触发 OOM 这个最常见引爆点 失去内存保护,单请求可能吃光内存,仅在有外部内存限制时考虑 两条(有争议)
改完重启所有 worker 配置对已存活 worker 不生效 一次 reload ---

⚠️ 每一项单独都只是"部分"。真正把可利用性压到最低,要组合使用 :enabled=0 + pm.max_requests=1 + 代理层拦 multipart。

reload 命令(改完必须执行,否则不生效)

bash 复制代码
# php-fpm(systemd)
systemctl reload php-fpm
# 或 remi SCL 版(本项目线上用的就是这种)
systemctl reload php56-php-fpm   # / php55-php-fpm
# 验证已生效
php-fpm -i | grep -i upload_progress.enabled   # 期望 Off

3. 按版本的差异

3.1 PHP 8.x(8.2 / 8.3 / 8.4 / 8.5)

  • 首选不是配置,是直接升小版本 :8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 已含完整根治补丁,升级即彻底解决。配置缓解只用于"升级前的几小时窗口"。
  • 8.5.x 额外加一项 :fatal_error_backtraces = 0(109619 的 backtrace 路径在 8.5 由此开关影响;5.x/7.x 没有这个 ini)。
ini 复制代码
; 升级前的临时缓解(8.x)
session.upload_progress.enabled = 0
fatal_error_backtraces = 0      ; 仅 8.5.x

3.2 PHP 7.x(7.0--7.4)

  • 没有官方发版 (php-7.4.34 等 tag 不存在)。配置层是你在"自编译"之前唯一能立刻做的事。
  • 可用项:session.upload_progress.enabled=0 + pm.max_requests=1 + 代理拦 multipart。没有 fatal_error_backtraces 开关。
  • 7.x 的 109619 风险靠 pm.max_requests=1 压(打断 worker 复用),这是 7.x 配置层能对 RCE 做的最有效一招。

3.3 PHP 5.x(5.5 / 5.6)------本项目线上现状

  • 同样无官方补丁。配置层能做的和 7.x 一致。
  • 特别提醒 :session.upload_progress.enabled 是可被逐请求 ini 覆盖的软开关,核心开发者明确说过"单独关它不够"。所以在 5.x 上,配置层只能当临时止血,不要当作已修复。
  • 5.x 推荐的临时组合:
ini 复制代码
; /opt/remi/php56/root/etc/php.ini 和 php55 两套都要改
session.upload_progress.enabled = 0
ini 复制代码
; php-fpm pool(api-port)
pm.max_requests = 1          ; 代价:QPS 下降,先压测再定;过渡期可先用较小值如 50

叠加 nginx 层:对确定不收上传的 location,拒绝 Content-Type: multipart/form-data。


4. 残余风险(必须写明,别自欺)

  • 配置层不改变漏洞代码是否存在 ,只是抬高利用门槛。upload_progress.enabled=0 不覆盖 109619 的 OPcache/backtrace 路径。
  • pm.max_requests=1 能打断跨请求复用,但在高并发下 fork 开销会变成新的瓶颈,属于"安全换性能"。
  • memory_limit=-1 换来的是"没有 OOM 引爆点",但也同时拆掉了内存保护,一个坏请求就能拖垮机器,除非外层(cgroup/容器)另有硬限制,否则不建议。

一句话 :配置层让你今晚能睡,但真正关门要靠自编译篇把官方补丁编进二进制。见 php2shell-缓解方案-自编译层.md。


参考

  • php-src 完整修复 commit 3584a98bda0(Replace bailout on OOM with UnwindExit)
  • php-src EOL 最小缓解分支 PHP-8.0-CVE-2026-109618-109619(commit 82f8f31b16a)
  • 已发版:php-8.2.35 / 8.3.36 / 8.4.27 / 8.5.12
  • GHSA-w8hw-w9fx-j79w / GHSA-6wmf-4rv5-p3rp
相关推荐
xbzb6 小时前
从零容器化部署 ECShop:Harbor 私有仓库 + 自定义 PHP 镜像 + LNMP 三容器
容器·php·harbor·镜像·仓库·ecshop
爱和冰阔落1 天前
【Linux网络】JsonCpp 怎么实现序列化?从 Request/Response 到网络计算器消息设计
linux·运维·网络·php
eggwyw1 天前
PHP8.5怎么用ffmpeg提取视频里的字幕轨道
开发语言·php
我叫黑大帅2 天前
PHP 常驻 Worker 中 MySQL 连接中断问题报告
后端·面试·php
国科安芯2 天前
人在回路中的总线:商业空间站环境控制与生命保障系统CANFD网络的可靠性与功能安全
网络·嵌入式硬件·安全·架构·php·抗辐射
码途行者2 天前
网站的SQL 注入:从攻击原理到防御措施
开发语言·sql·php
老秦包你会2 天前
计算机网络第二课 ----Socket(套接字)编程预备
开发语言·计算机网络·php
迪康coolmu3 天前
出差终端数据安全落地实战:基于迪康端点安全一体化管理系统的四道防线实践
运维·服务器·经验分享·笔记·其他·安全·php
普通人63 天前
PHP文件读写完全指南
开发语言·php·1024程序员节
vipxieliang3 天前
ThinkORM 3.0 入门:强类型模型定义与查询构造器
后端·php·thinkphp