================================================================================
 PHP 5.5  php-fpm 临时加固建议
 php2shell: CVE-2026-109618 (RCE via OOM corruption)
           CVE-2026-109619 (RCE via stale global state)
================================================================================

【一、版本状态】
适用版本   : PHP 5.5.x
受影响区间 : PHP 5.5.x 全系 (没有任何官方修复版本号)
修复情况   : 【无补丁、无 backport】官方本次不覆盖该分支。
分支状态   : 已 EOL (2016-07)
建议       : 短期隔离到 WAF/内网之后; 中期必须迁移到受支持分支 (8.3+)
分支末版   : 5.5.38  —— 该版本【同样受影响】, 本分支不存在任何安全版本号

常见配置路径(以实际环境为准):
  pool 文件 : /etc/php5/fpm/pool.d/www.conf
  php.ini   : /etc/php5/fpm/php.ini
  服务名    : php5-fpm

================================================================================
【二、php-fpm pool 段配置】

用法: 把下面整段粘贴进 pool 文件的 [www] 段【内部】。
      不要单独存成 pool.d 目录下的新文件 —— 那会被 FPM 当成新建一个 pool,
      配置不会作用到 [www], 等于白改。
      必须用 php_admin_value[] / php_admin_flag[]: 应用里的 ini_set() 和 .user.ini
      都无法覆盖 admin 级设置; 用普通 php_value 会被应用改回去。

--------------------------------------------------------------------------------
; >>> php2shell mitigation BEGIN >>>

; -- CVE-2026-109618: 去掉"可被攻击者主动触发的" PHP 内存上限失败 --
php_admin_value[memory_limit] = -1
;   注意: -1 = PHP 层不设限, 老应用内存泄漏可能吃满整机。
;         必须配 cgroup / systemd 兜底, 且【禁止】用 RLIMIT_AS / RLIMIT_DATA 代替 ——
;         那会自己制造"有漏洞的分配失败", 反而打开 CVE-2026-109618。

; -- 请求体上界与输入复杂度 --
php_admin_value[post_max_size] = 8M          ; 无上传业务 8M; 必须有上传改 32M, 别更大
php_admin_value[upload_max_filesize] = 2M    ; 必须严格小于 post_max_size
php_admin_value[max_file_uploads] = 20       ; multipart part 数
; 本分支无 max_input_vars 指令 (5.3.9+ 才有), 该行不要用
php_admin_value[max_input_nesting_level] = 32 ; 数组嵌套深度 (默认 64, 攻击面偏大)

; -- CVE-2026-109619: 已确认路径的直接开关 --
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[session.upload_progress.cleanup] = 1
php_admin_value[session.upload_progress.freq] = 100%
php_admin_value[session.upload_progress.min_freq] = 100
;   必须写在 pool / php.ini 级。ini_set() 与 .user.ini 在请求解析之后才生效, 拦不住。

; -- 诊断输出 (官方明确说明: 这拦不住漏洞, 只是收敛触发面与信息泄露) --
php_admin_flag[display_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php-fpm/www-error.log

; -- 注意: fatal_error_backtraces 是 PHP 8.5 新增指令, 本分支不存在 --
;    写了会让 php-fpm -t 报 unknown directive, FPM 起不来, 千万别照抄 8.5 的配置。

; -- worker 卫生: 缩短"脏状态"存活窗口, 辅助缓解 CVE-2026-109619 --
pm.max_requests = 500          ; 每个 worker 处理 500 个请求后回收重建
                               ; 若 pool 里已有 pm.max_requests, 别留两个(后面的会覆盖前面的)

; -- 顺手收敛 (与本次 CVE 无关, 但同机上大概率并存的旧洞) --
security.limit_extensions = .php   ; 配合 nginx 防 CVE-2019-11043 等路径拼接类漏洞
catch_workers_output = yes
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 10s

; -- 反模式: 别把下面这些当防护 --
;   request_terminate_timeout / max_execution_time 设得太小 = 制造攻击者可触发的执行超时,
;   官方对 CVE-2026-109619 的缓解建议里点名要求"修掉可被外部触发的 fatal error 与执行超时"。
; <<< php2shell mitigation END <<<
--------------------------------------------------------------------------------

================================================================================
【三、php.ini 同步项】(CLI / php-cgi 不走 pool, 建议同步写一份)

  memory_limit = -1
  post_max_size = 8M
  upload_max_filesize = 2M
  max_file_uploads = 20
  max_input_nesting_level = 32
  session.upload_progress.enabled = 0
  display_errors = Off
  log_errors = On

另需检查被覆盖的风险点:
  find /var/www -name ".user.ini" -exec grep -H . {} ;
  grep -rnE "ini_set\((memory_limit|post_max_size|upload_max_filesize|session)" /var/www --include="*.php"
  (php_admin_* 会让它们失效, 但要看清业务是否依赖这些覆盖)

================================================================================
【四、Web 服务器 / 代理侧 (PHP 之前就挡掉)】

nginx:
  client_max_body_size 8m;               # 与 post_max_size 对齐, 最好略小
  client_body_buffer_size 128k;
  client_header_buffer_size 4k;
  large_client_header_buffers 4 8k;      # header 数量与大小上界
  client_body_timeout 10s;
  client_header_timeout 10s;
  limit_req zone=req_limit burst=20 nodelay;

  不需要文件上传的站点, 直接拒绝 multipart (最有效的一条):
    map $http_content_type $block_multipart {
        default                             0;
        "~*^multipart/form-data(?:\s*;|$)"   1;
    }
    if ($block_multipart) { return 403; }

  nginx + php-fpm 还必须防 CVE-2019-11043:
    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        try_files $fastcgi_script_name =404;   # 交给 PHP 前先校验文件存在
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    自查: egrep -Rin "fastcgi_split_path" /etc/nginx/   (有输出 = 命中前置配置)

Apache (mod_php, 官方认定风险最高的 SAPI):
  <VirtualHost *:80>
      php_admin_flag session.upload_progress.enabled Off
      php_admin_value memory_limit -1
      php_admin_value post_max_size 8M
      php_admin_value upload_max_filesize 2M
      LimitRequestFields 100
      LimitRequestFieldSize 8190
      LimitRequestBody 8388608      ; 8M, 覆盖无可用 Content-Length 的请求
  </VirtualHost>
  改完: apachectl configtest && apachectl restart   (prefork 需全量重启)

WAF / CDN:
  不要只匹配单行干净的 name="PHP_SESSION_UPLOAD_PROGRESS"。PHP 的 multipart 解析器
  接受折叠头、无冒号行、缺 form-data、闭合引号后的垃圾字符, 精确匹配会漏。
  且 session.upload_progress.name 可改名, 默认名只是可靠指标之一。

================================================================================
【五、改完必做】

  1) 语法校验:
       php-fpm -t
  2) 重启服务 (必须重启所有 worker, 只 reload 主进程不够):
       systemctl restart php5-fpm
       # 容器场景: docker compose up -d --force-recreate php
  3) 确认 worker 全部是新起的:
       ps -eo pid,lstart,args | grep php-fpm
  4) 用 HTTP 探针确认实际生效值 (CLI 的 php -i 不代表 FPM):
       cp php2shell-probe.php /var/www/html/__probe.php
       curl -s http://127.0.0.1/__probe.php
       rm -f /var/www/html/__probe.php
  5) 回滚: cp -a <备份的 pool 文件> <原路径> && systemctl restart php5-fpm

  cgroup / systemd 兜底 (memory_limit=-1 之后必须做):
       systemctl set-property php5-fpm.service MemoryMax=512M
       systemctl set-property php5-fpm.service OOMPolicy=continue   ; 只杀被 OOM 的那个 worker

【六、入侵迹象排查】

  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
  awk '$9 ~ /^5[0-9][0-9]$/' /var/log/nginx/access.log | wc -l    # 5xx 突增
  grep -l "upload_progress" /var/lib/php/session/sess_* 2>/dev/null | head -20

================================================================================
【免责声明】

  临时加固操作无法保证堵住漏洞, 仅为升级到最新版本争取时间, 请尽快升级到最新版。
  本文件为公开安全公告的整理与运维实践汇总, 不构成任何形式的安全保证或担保;
  请以 php.net 官方公告与实际环境验证结果为准。修改配置前请务必备份,
  并在自有或已授权的系统上使用。
================================================================================
