公司动态

PHP2Shell漏洞回顾与修复指南
公司动态 2026-11-11 4 阅读

PHP2Shell漏洞回顾与修复指南

小泥巴 重庆市小泥吧科技有限公司 2026-11-11

一句话版:能升级就先升级——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 均为 9.2,无需认证、无需用户交互,攻击请求在应用代码执行之前就已生效。由于细节与 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

修复版本:8.2.35 / 8.3.36 / 8.4.27 / 8.5.12。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 与它相关,而且它只是已确认的一条路径;109618 是 OOM 引发的状态损坏,跟 session 无关
CVSS 10.0,史上最严重官方评分是 9.2(v4.0),AC——利用条件偏苛刻,不等于“随便一打就穿”
ThinkPHP 出了新漏洞漏洞在 PHP 引擎层,与框架无关,所有 PHP 站点都是同一处境;唯一跟框架有关的变量,是应用的 session 是否把请求级数据写进了 PHP 的全局会话状态

对号入座:你的运行方式该怎么办

你的运行方式怎么办
think-swoole(常驻协程)已确认的利用路径基本不成立,应用层通常无需改动,保持运行时更新即可(见方案一)
FPM / mod_php + TP 6.0+① 升级 PHP(唯一完整修复);② 过渡期三件套:关上传进度、走 TP 内置 session、收紧限额(见方案二与加固清单)
FPM / mod_php + TP 5.x方案二对其不适用——TP5 的 session 本质是原生 session 封装,须先升级到 TP 6.0+ 再按上行处理
任何模式无法立即升级又暴露公网:先在 WAF / 网关限制访问,或临时下线

方案一:think-swoole 用户——风险最低,但别当免死金牌

Swoole 常驻模式下,两个 CVE 的已验证利用链都缺少必要环节,四条机制依据值得说清楚:

  • 不经过 PHP 的 multipart 解析器:请求体由 Swoole 自行解析并填充 $_POST / $_FILES,109618 的入口(PHP 的 multipart 解析与内存耗尽)不参与;PHP_SESSION_UPLOAD_PROGRESS 驱动的上传进度回调也不会触发,109619 的已确认路径之一随之消失;

  • 没有按请求生效的 INI:.htaccess / php_value / PHP_VALUE 这类覆盖在 Swoole 下不生效,109619 所需的“初始化阶段触发告警”入口大幅减少;

  • Session 自成体系:think-swoole 基于 swoole_table + ThinkPHP 缓存的独立 Session 实现,不走 session_start(),应用不会向 PHP 的全局会话状态发布请求级数据;

  • 仍要做的两件事:Swoole 扩展与 PHP 运行时保持更新(发行版会回移植补丁);避免在攻击者可达路径(上传、导入、错误页、析构)上制造致命错误和超时——那正是 109619 里“留下残留状态”的第一个请求。

判断依据说明:以上是基于公开通告与框架源码的机制分析,不是官方结论。如果你的 think-swoole 应用里仍在调用原生 $_SESSION / session_start(),或装有会触发 per-request INI 的扩展,请按方案二处理,不要套用“免处理”。

方案二:FPM / mod_php 走 TP 内置 session(仅 TP 6.0+)

版本前提:TP 6.0 / 6.1 / 8.x 的 think\session\Store 是纯 PHP 实现——读写全部走自有驱动(file 落 runtime/session/,redis / memcached 同理),全程不调用 session_start() / session_set_save_handler(),因此应用不会把请求级数据发布到 PHP 的全局会话状态,官方验证的 FPM 应用依赖型利用链随之断掉。TP 5.x 不适用:其 think\Session 是原生 session 的封装(session_set_save_handler() + session_start() + $_SESSION),必须先升级框架。

配置本身很简单,用内置驱动即可:

// config/session.phpreturn [
    'type'       => 'redis',   // 或 file / memcached / memcache
    'auto_start' => true,];

三条注意:

  1. 统一用 session() 助手或 Session 门面,不要混用 $_SESSION、session_start()、session_set_save_handler() 等原生 API,第三方扩展同样要排查;

  2. 必须配套关闭上传进度——该处理器在引擎层运行,不要求应用调用 session_start(),因此还存在与 TP 无关的利用链;

  3. 这是纵深防御而非完整修复,完整修复仍然只有升级 PHP。

; php.ini 或 FPM pool,启动期生效
session.upload_progress.enabled = Off

不要放在 .htaccess 里。每请求生效的 INI 覆盖本身就是 109619 利用链的一环,用它做防护等于往火上浇油。ini_set() 同样无效——PHP 在应用代码运行前就处理完上传了,函数会直接返回 false。

过渡期加固清单(无法立即升级时)

PHP 侧:

; 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       = 20max_input_vars         = 1000max_input_nesting_level = 64; file_uploads         = Off      ; 业务确实没有上传时再开
memory_limit           = -1       ; 管理员强制设置,让 OOM 路径打不中(见下方说明)

关于内存:PHP 给出的部分缓解是“由管理员显式设置 memory_limit=-1,让请求不会走到 OOM 分支”,同时配一个很小的 post_max_size。反过来说,不要为了“省内存”去调小 memory_limit,也不要用 RLIMIT_AS / RLIMIT_DATA 给 PHP 进程加 OS 级内存上限——那恰好是把请求推进 OOM 的路径。

Web 服务器侧: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; }

WAF 侧:拦掉任何请求体里带上传进度字段的请求,作为 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 的进程

注意事项

  • 关 display_errors、加 @、改 error_reporting 都没用:漏洞发生在引擎层,不在你的错误处理逻辑里;

  • 只封 PHP_SESSION_UPLOAD_PROGRESS 不等于修复:它挡住的是 109619 的已知路径,109618 走的是 multipart 内存耗尽,且不排除有其它变体;

  • 打了 WAF 规则不等于打完补丁:WAF 解析 multipart 的方式与 PHP 不同,只能算一层缓冲;

  • 不要运行来源不明的“一键检测脚本”和 PoC:漏洞细节在补丁前就已泄露,这类脚本本身就是投毒重灾区。


相关标签:

发表评论:

评论记录:

未查询到任何数据!
QQ咨询
回电话
回拨通话

我们稍后回拨您的电话

座机请加区号

微信联系
微信扫一扫
微信二维码

扫码加微信