适用场景:不改二进制、不重编译 ,只靠运行期配置争取时间。
结论先行:配置层能显著降低可利用性,但官方核心开发者明确说过------单独关
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(commit82f8f31b16a) - 已发版:
php-8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 - GHSA-w8hw-w9fx-j79w / GHSA-6wmf-4rv5-p3rp