PHP 重大RCE漏洞的ThinkPHP站点应对速查
流年 · 1天前
2026 年 10 月 PHP 核心两个 9.2 分未认证 RCE 的 ThinkPHP 应对速查:think-swoole 按机制分析基本免处理,FPM/mod\_php 用户升级 + 配置加固清单
> 一句话版:能升级就先升级——8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 或发行版回移植版本。升不了,就关掉 `session.upload_progress`、收紧请求体限额、收窄 multipart 入口;think-swoole 用户按机制分析风险极低,但仍应跟进运行时更新。
## 事件速览
2026 年 10 月 21 日 14:00 UTC,PHP 官方发布带外安全版本,修复两个核心引擎漏洞,CVSS v4.0 均为 <strong>9.2</strong>,无需认证、无需用户交互,攻击请求在应用代码执行之前就已生效。由于细节与 PoC 在补丁发布前泄露,社区将其称为 PHP2Shell;SANS 一度将 infocon 提升到黄色,Cloudflare 报告已观测到在野利用。
| 编号 | 成因 | 攻击者怎么打 | 影响面 |
| --- | --- | ------ | --- |
| **CVE-2026-109618** | 内存耗尽(OOM)打断请求初始化,清理阶段把半初始化的数据当成有效数据 | 用 multipart 请求把 PHP 的内存推到耗尽:不带 `Content-Length` 的 multipart 可绕过 `post_max_size`,请求头数量无上限,`max_file_uploads` 不计空文件 | mod\_php 已验证可利用;FPM / php-cgi / FrankenPHP / LiteSpeed 同样在风险名单 |
| **CVE-2026-109619** | 请求级全局状态未复位,形成 UAF(释放后使用) | 同一 worker 上先后两个请求:前一个以致命错误、OOM 或超时收场并留下残留状态,后一个在初始化阶段读到它 | 同上;已确认路径包括 session 上传进度(默认开启)与 PHP 8.5 的 `fatal_error_backtraces` |
修复版本:<strong>8.2.35 / 8.3.36 / 8.4.27 / 8.5.12</strong>。PHP 7.4 / 8.0 / 8.1 只提供源码级回移植,官方不再发版;Ubuntu 已发布 USN-8948-1(覆盖 22.04 / 24.04 / 26.04 / 26.10),其余发行版以各自追踪页为准。
> 关于“影响所有版本”:PHP 5 以来的版本在机制上都在风险范围,但官方只为 8.2–8.5 出构建。所以判断一台机器是否已修复,认发行版安全公告和包版本,而不是 `php -v` 的主版本号。
## 先纠正三个流传的说法
漏洞刚公开时各种版本的“技术解读”满天飞,其中三个错误流传最广:
| 流传说法 | 实际情况 |
| ---- | ---- |
| 两个漏洞都是 session 上传进度的 UAF | 只有 109619 与它相关,而且它只是<strong>已确认的一条路径</strong>;109618 是 OOM 引发的状态损坏,跟 session 无关 |
| CVSS 10.0,史上最严重 | 官方评分是 9.2(v4.0),AC——利用条件偏苛刻,不等于“随便一打就穿” |
| ThinkPHP 出了新漏洞 | 漏洞在 PHP 引擎层,与框架无关,所有 PHP 站点都是同一处境;唯一跟框架有关的变量,是应用的 session 是否把请求级数据写进了 PHP 的全局会话状态 |
## 对号入座:你的运行方式该怎么办
| 你的运行方式 | 怎么办 |
| ------ | --- |
| <strong>think-swoole</strong>(常驻协程) | 已确认的利用路径基本不成立,<strong>应用层通常无需改动</strong>,保持运行时更新即可(见方案一) |
| **FPM / mod\_php + TP 6.0+** | ① 升级 PHP(唯一完整修复);② 过渡期三件套:关上传进度、走 TP 内置 session、收紧限额(见方案二与加固清单) |
| **FPM / mod\_php + TP 5.x** | 方案二对其<strong>不适用</strong>——TP5 的 session 本质是原生 session 封装,须<strong>先升级到 TP 6.0+</strong> 再按上行处理 |
| 任何模式 | 无法立即升级又暴露公网:先在 WAF / 网关限制访问,或临时下线 |
## 方案一:think-swoole 用户——风险最低,但别当免死金牌
Swoole 常驻模式下,两个 CVE 的已验证利用链都缺少必要环节,四条机制依据值得说清楚:
* <strong>不经过 PHP 的 multipart 解析器</strong>:请求体由 Swoole 自行解析并填充 `$_POST` / `$_FILES`,109618 的入口(PHP 的 multipart 解析与内存耗尽)不参与;`PHP_SESSION_UPLOAD_PROGRESS` 驱动的上传进度回调也不会触发,109619 的已确认路径之一随之消失;
* <strong>没有按请求生效的 INI</strong>:`.htaccess` / `php_value` / `PHP_VALUE` 这类覆盖在 Swoole 下不生效,109619 所需的“初始化阶段触发告警”入口大幅减少;
* <strong>Session 自成体系</strong>:think-swoole 基于 `swoole_table` + ThinkPHP 缓存的独立 Session 实现,不走 `session_start()`,应用不会向 PHP 的全局会话状态发布请求级数据;
* <strong>仍要做的两件事</strong>:Swoole 扩展与 PHP 运行时保持更新(发行版会回移植补丁);避免在攻击者可达路径(上传、导入、错误页、析构)上制造致命错误和超时——那正是 109619 里“留下残留状态”的第一个请求。
> 判断依据说明:以上是基于公开通告与框架源码的机制分析,不是官方结论。如果你的 think-swoole 应用里仍在调用原生 `$_SESSION` / `session_start()`,或装有会触发 per-request INI 的扩展,请按方案二处理,不要套用“免处理”。
## 方案二:FPM / mod\_php 走 TP 内置 session(仅 TP 6.0+)
<strong>版本前提</strong>:TP 6.0 / 6.1 / 8.x 的 `think\session\Store` 是纯 PHP 实现——读写全部走自有驱动(file 落 `runtime/session/`,redis / memcached 同理),<strong>全程不调用 `session_start()` / `session_set_save_handler()`</strong>,因此应用不会把请求级数据发布到 PHP 的全局会话状态,官方验证的 FPM 应用依赖型利用链随之断掉。<strong>TP 5.x 不适用</strong>:其 `think\Session` 是原生 session 的封装(`session_set_save_handler()` + `session_start()` + `$_SESSION`),必须先升级框架。
配置本身很简单,用内置驱动即可:
```
// config/session.php
return [
'type' => 'redis', // 或 file / memcached / memcache
'auto_start' => true,
];
```
三条注意:
1. 统一用 `session()` 助手或 `Session` 门面,<strong>不要混用</strong> `$_SESSION`、`session_start()`、`session_set_save_handler()` 等原生 API,第三方扩展同样要排查;
2. <strong>必须配套关闭上传进度</strong>——该处理器在引擎层运行,不要求应用调用 `session_start()`,因此还存在与 TP 无关的利用链;
3. 这是<strong>纵深防御而非完整修复</strong>,完整修复仍然只有升级 PHP。
```
; php.ini 或 FPM pool,启动期生效
session.upload_progress.enabled = Off
```
> 不要放在 `.htaccess` 里。每请求生效的 INI 覆盖本身就是 109619 利用链的一环,用它做防护等于往火上浇油。`ini_set()` 同样无效——PHP 在应用代码运行前就处理完上传了,函数会直接返回 false。
## 过渡期加固清单(无法立即升级时)
<strong>PHP 侧</strong>:
```
; php.ini / FPM pool 配置
session.upload_progress.enabled = Off
fatal_error_backtraces = 0 ; 仅 PHP 8.5+,另一条已确认的 109619 路径
post_max_size = 8M ; 按业务收紧,并在 Nginx/Apache 侧独立强制请求体上限
max_file_uploads = 20
max_input_vars = 1000
max_input_nesting_level = 64
; file_uploads = Off ; 业务确实没有上传时再开
memory_limit = -1 ; 管理员强制设置,让 OOM 路径打不中(见下方说明)
```
> 关于内存:PHP 给出的部分缓解是“由管理员显式设置 `memory_limit=-1`,让请求不会走到 OOM 分支”,同时配一个很小的 `post_max_size`。反过来说,<strong>不要</strong>为了“省内存”去调小 `memory_limit`,也<strong>不要</strong>用 `RLIMIT_AS` / `RLIMIT_DATA` 给 PHP 进程加 OS 级内存上限——那恰好是把请求推进 OOM 的路径。
<strong>Web 服务器侧</strong>:Nginx 收紧 `client_max_body_size`;对确认不接收上传的路由,直接拦掉 `Content-Type: multipart/form-data`。
```
# http {} 段
map $http_content_type $is_multipart { default 0; "~*^\s*multipart/form-data" 1; }
map $uri $upload_route { default 0; "~^/api/upload$" 1; }
# server {} 段
set $mp_block "$is_multipart$upload_route";
if ($mp_block = "10") { return 415; }
```
<strong>WAF 侧</strong>:拦掉任何请求体里带上传进度字段的请求,作为 PHP 之外的独立一层。
```
SecRule ARGS_POST_NAMES "@streq PHP_SESSION_UPLOAD_PROGRESS" \
"id:1026109618,phase:2,deny,status:403,log,t:none,msg:'PHP upload progress field'"
```
需要 `SecRequestBodyAccess On`;字段名若改过 `session.upload_progress.name`,规则同步替换。共享主机或官方 Docker 镜像等改不了主 php.ini 的场景,可以用站点根目录的 `.user.ini` 或在 `/usr/local/etc/php/conf.d/` 下加一份配置后重建镜像。
## 应急清单
| 优先级 | 动作 |
| --- | --- |
| **P0 · 立即** | 升级 PHP 至 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 或发行版回移植版本,重启 FPM / Web;无法升级且暴露公网 → WAF 限流、收窄 multipart 入口或直接下线 |
| **P1 · 24 小时内** | `session.upload_progress.enabled = Off` 并重启 worker;PHP 8.5 设 `fatal_error_backtraces = 0`;收紧 `post_max_size` 等限额;Nginx 侧限制请求体并拦截非上传路由的 multipart |
| **P2 · 一周内** | swoole 用户保持运行时更新;FPM 用户确认 session 走框架内置管理、无原生混用;清查容器镜像与面板、CDN 回源、第三方软件内嵌的 PHP;开启 `E_ALL` + `log_errors`,并监控 Web 用户派生 `sh` / `curl` / `wget` 的进程 |
## 注意事项
* <strong>关 `display_errors`、加 `@`、改 `error_reporting` 都没用</strong>:漏洞发生在引擎层,不在你的错误处理逻辑里;
* <strong>只封 `PHP_SESSION_UPLOAD_PROGRESS` 不等于修复</strong>:它挡住的是 109619 的已知路径,109618 走的是 multipart 内存耗尽,且不排除有其它变体;
* <strong>打了 WAF 规则不等于打完补丁</strong>:WAF 解析 multipart 的方式与 PHP 不同,只能算一层缓冲;
* <strong>不要运行来源不明的“一键检测脚本”和 PoC</strong>:漏洞细节在补丁前就已泄露,这类脚本本身就是投毒重灾区。
<br>
推荐资讯
-
PHP 重大RCE漏洞的ThinkPHP站点应对速查
2026年10月22日
-
调试技能这件事,以后可以交给 AI 自己去做了
2026年09月09日
-
我把一段 4 秒的科技馆视频,教 AI 变成了一个技能
2026年09月06日
-
给员工配一个 AI,还是给公司建一套 AI?
2026年08月31日
-
官方 Skill 市场正式上线:一键解锁企业级 AI 能力
2026年08月29日
最新资讯
-
PHP 重大RCE漏洞的ThinkPHP站点应对速查
2026年10月22日
-
调试技能这件事,以后可以交给 AI 自己去做了
2026年09月09日
-
我把一段 4 秒的科技馆视频,教 AI 变成了一个技能
2026年09月06日
-
给员工配一个 AI,还是给公司建一套 AI?
2026年08月31日
-
官方 Skill 市场正式上线:一键解锁企业级 AI 能力
2026年08月29日