欢迎光临
我们一直在努力

PHP2Shell(CVE-2026-109618 / 619)IPS 自定义规则字段级配置指南

一、从漏洞机理反推:IPS 究竟能看见什么

漏洞机理(官方公告)

网络侧可观测特征

可检测位置

multipart 请求没有可用 Content-Length,绕过 post_max_size 初检

POST + Content-Type: multipart/form-data,但无 Content-Length 头,或使用 chunked

请求头

单个 part 内塞入不限数量的 header

请求体内出现异常密集的 header 行(\\r\\nxxx: yyy 连续多行)

请求体

空文件控件不计入 max_file_uploads,仍生成元数据数组

请求体内大量 filename="" 的 part

请求体

嵌套字段名成倍放大数组开销

name="a[b][c][d][e]…" 深度嵌套

请求体

应用侧 OOM:攻击者可控输入导致超大分配

请求体/参数体量异常,或无特征(这条 IPS 基本测不到)

请求体(弱)

CVE-2026-109619 的 session 上传进度路径

请求体中出现 PHP_SESSION_UPLOAD_PROGRESS 字段名

请求体

已知攻击者工具/探针

上传文件名 MARKER_[8位hex].txt;session 前缀 fprint、dp;工具串 p2shell

请求体

已知攻击者基础设施

源 IP 206.188.197.105;外连端口 8888 / 8899 / 9999

网络层 / 请求体

内存泄露路径(PHPSESSID 泄漏堆内存)

响应头 Set-Cookie: PHPSESSID= 值异常长或畸形

响应头(很多 IPS 默认不检测响应,需显式开启)

利用后果

同一源 IP 的异常 multipart 之后紧随大量 500

需 SIEM 关联,IPS 单条规则做不了

结论:IPS 能覆盖的是请求构造特征和已知 IOC这两块;应用侧 OOM 路径和"是否真的被打成功"这两件事,IPS 管不了,要靠主机侧(PHP Worker 派生子进程)和日志关联。

二、规则字段结构(通用 IPS 图形化界面对照表)

不管你用的是哪一款 IPS/WAF,自定义规则基本都是下面这些字段,照着填即可:

规则字段

本场景取值

说明

规则名称

PHP2Shell-multipart-no-content-length 等

建议带 CVE 与特征名,便于后续审计

规则类型 / 协议

HTTP

需勾选"HTTP 协议解码"

方向 / 区域

外网区/互联网 → DMZ 或服务区

内网横向场景可再建一条 any→any

源地址

any(或 $EXTERNAL_NET)

IOC 规则填具体 IP

目的地址

Web 服务器地址组

精确到资产组,减少误报面

目的端口

80, 443, 8080 等

443 必须已开启解密

匹配项 1:HTTP 方法

等于 / 包含 POST

部分产品字段名 http.method

匹配项 2:请求头 Content-Type

包含 multipart/form-data(不区分大小写)

字段名 http.header / http_request_header

匹配项 3:请求头 Content-Length

不存在,或值为 0

字段名同上;不存在用"取反/不存在"运算符

匹配项 4:请求体关键字

包含 PHP_SESSION_UPLOAD_PROGRESS

字段名 http.request_body / http_client_body

匹配项 5:请求体正则

MARKER_[0-9a-fA-F]{8}\\.txt

开 PCRE,不区分大小写

匹配项 6:请求体正则

name\\s*=\\s*"[^"]{0,120}(?:\\[[^\\]]{0,40}\\]){8,}

嵌套 ≥8 层

匹配项 7:请求体正则

(?:\\r\\n[^\\r\\n]{1,160}:[ ]){25,}

单 part 内 25+ 个 header 行

匹配项 8:请求体大小

> 业务基线(建议先按 post_max_size 设 8M/32M)

字段名 request_body_size / Content-Length

匹配项 9:响应头(需开启响应检测)

正则 Set-Cookie\\s*:\\s*PHPSESSID=[^;\\r\\n]{48,}

字段名 http.response_header

匹配项 10:URI 例外

不等于 业务真实上传接口清单

用白名单降低"非上传接口出现 multipart"的误报

动作

分级:观察期=仅告警 → 稳定后=阻断;IOC 类=直接阻断

见第五节分级表

阈值 / 频率

track by_src, count 5, seconds 60 一类

用计数替代"正则计数",更稳

日志

留存原始请求头 + 请求体前 N 字节

出事回溯要用;注意别把完整含敏感数据的 body 长期留存

例外 / 白名单

业务上传接口、已知扫描器、内网监控探针

必须先跑观察期再定

规则元数据

cve: CVE-2026-109618, CVE-2026-109619;reference 指向官方公告

便于后续检索与合规说明


三、逐条规则(Suricata 6/7 语法 + 字段说明 + 误报处理)

语法以 Suricata 为例。Snort 3 字段名:http_method / http_header / http_client_body / http_uri / http_stat_code;商业 IPS 按第二节字段表对照填写。SID 使用 9100000 段,请与你现有编号体系对齐。

规则 1:multipart POST 缺失 Content-Length(高价值)

  • 匹配字段:http.method(POST)、http.header(Content-Type 含 multipart)、http.header(不存在 Content-Length:)
  • 对应机理:官方列出的第一条 OOM 绕过手法——没有可用 Content-Length 的 multipart 请求可绕过初始 post_max_size 检查
  • 误报:HTTP/1.0 客户端、部分老旧代理、chunked 上传。若你的版本不支持 sticky buffer 内取反,改为 http.header; pcre:"/^Content-Length\\s*:\\s*(0)?\\s*$/mi";
  • 动作建议:观察期告警,稳定后阻断

规则 2:请求体出现 PHP_SESSION_UPLOAD_PROGRESS( hunting 首选)

  • 匹配字段:http.request_body,关键字 PHP_SESSION_UPLOAD_PROGRESS
  • 价值:这是 CVE-2026-109619 已确认利用链(session 上传进度作为 producer/consumer)的直接信号,也是蜜罐观测到的两条利用手法之一
  • 误报:⚠️ 业务本身使用 PHP 上传进度功能会触发。因此建议先设为"仅告警",跑满一个业务周期后按 URI 白名单收敛
  • 注意:该功能默认开启,且不需要应用调用 session_start()

规则 3:已知 IOC 文件名 MARKER_

  • 匹配字段:http.request_body 正则 MARKER_[0-9a-fA-F]{8}\\.txt
  • 动作:直接阻断,误报概率极低

规则 4:字段名深度嵌套(数组开销放大)

  • 匹配字段:http.request_body 正则,统计 name="…" 内方括号嵌套层数 ≥ 8
  • 机理:官方明确"嵌套字段名会成倍放大数组生成开销"
  • 调参:{8,} 是嵌套层数阈值。PHP max_input_nesting_level 默认值较高,建议先用 810 观察,别一上来设 23(正常表单也可能有数组)

规则 5:单个 part 内异常密集的 header(启发式)

  • 匹配字段:http.request_body 正则,25 个以上形如 \\r\\nxxx: yyy 的连续行
  • 机理:官方列出"单个 part 可包含不限数量的 header,其在 PHP 内部的内存表示远大于线上表示"
  • ⚠️ 这是启发式规则,性能开销较大,务必加 threshold 限速,并优先只在高价值资产上开

规则 6:大量空文件控件(用阈值计数替代正则计数)

  • 匹配字段:http.request_body 正则 filename="";计数交给 threshold(同源 60 秒内 20 次)
  • 机理:官方明确"空文件控件不计入 max_file_uploads,但仍生成正常的文件元数据数组"
  • 为什么不用正则计数:PCRE 不支持"出现 N 次"这种计数语义,用规则引擎的 threshold 做计数既准确又省性能——这是写 IPS 规则的一个通用技巧

规则 7:已知攻击者 IOC(网络层,直接阻断)

  • 匹配字段:源 IP;以及出向目的端口 8888 / 8899 / 9999
  • 说明:8888 为带外交互监听器、8899 为轮换代理池端点、9999 为暴露的操作者工作目录
  • 动作:直接阻断。出向那条建议先告警——因为 8888/9999 也是常见业务端口,需先确认基线

规则 8:响应头 PHPSESSID 异常(内存泄露路径特征)

  • 匹配字段:http.response_header(必须显式开启响应方向检测,很多 IPS 默认只检请求)
  • 机理:Wiz 指出内存泄露路径会把进程内存通过 PHPSESSID 响应 Cookie 泄漏出来,表现为异常大或畸形的 Cookie 值
  • 基线:PHP 默认 session id 为 26 位十六进制。阈值 48 需按你应用的实际 session id 长度校准
  • 处置:命中即视为可能发生内存泄露,按凭据泄露处理并轮换

四、规则清单汇总(给领导/变更单用)

SID

名称

置信度

误报风险

建议动作

9100001

multipart 缺失 Content-Length

中高

中(HTTP/1.0、chunked)

观察→阻断

9100002

请求体含 PHP_SESSION_UPLOAD_PROGRESS

高

中高(业务可能自用)

仅告警(先)

9100003

MARKER_[8hex].txt IOC

极高

极低

直接阻断

9100004

字段名深度嵌套 ≥8

中

中

告警

9100005

part 内 header 行 ≥25

中(启发式)

中

告警 + 限速

9100006

空文件控件高频

中

中

告警(阈值计数)

9100007

已知攻击者 IP

极高

无

直接阻断

9100008

出向 8888/8899/9999

中

中(常见端口)

告警(先)

9100009

PHPSESSID 值异常

中高

中(需校基线)

告警(触发取证)


五、动作与阈值分级建议

阶段

时间

动作

目的

第一阶段

上线后 24~48 小时

全部仅告警 + 记录原始请求头/请求体前 N 字节

摸清误报来源

第二阶段

误报收敛后

IOC 类(9100003/9100007)改阻断;其余保持告警 + 阈值限速

挡住已知威胁

第三阶段

打完 PHP 补丁后

保留告警,不删除

补丁前的历史攻击回溯 + 后续变种监测

六、上线步骤(按顺序做,别跳)

  • 确认 HTTPS 解密已覆盖目标站点——没解密就先停在这里,规则形同虚设;
  • 调大 HTTP 请求体检测深度,确保能覆盖 multipart 头部区;
  • 开启响应方向检测(为规则 9100009);
  • 导入规则,动作全部设为"仅告警",跑 24~48 小时;
  • 按 URI/源 IP 建白名单:业务真实上传接口、内部扫描器、监控探针;
  • 收敛后按第四节表格调整动作;
  • 同步推进 PHP 升级——规则只是争取时间;
  • 留存日志:Web、IPS、PHP-FPM、主机日志都留,用于回溯 10 月 17 日之后的记录(利用尝试早于公开披露)。
  • 七、检测盲区(写进报告里,别让领导以为上了规则就安全)

    盲区

    说明

    弥补手段

    HTTPS 未解密

    看不到任何 body 特征

    开启解密或卸载

    body 检测深度不足

    特征在检测窗口之外

    调大深度

    分片 / chunked 绕过

    特征被切到多个 TCP 段或 chunk

    确认 IPS 做了 HTTP 重组(多数商业 IPS 有此开关)

    无 Content-Length + 超长流式 body

    IPS 无法预先判定大小

    在 Nginx/Apache 层做硬性 client_max_body_size / LimitRequestBody

    应用侧 OOM 路径

    与 multipart 无关,攻击者可控输入导致大分配

    IPS 测不到,只能靠 memory_limit=-1 缓解 + 应用层输入约束

    是否已被打成功

    利用发生在应用层之下,无 WebShell、进程命令行正常

    主机侧:监测 PHP/Web 进程派生 /bin/sh、curl、wget

    响应侧 Cookie 异常

    默认不检响应

    显式开启响应检测

    赞(0)
    未经允许不得转载:171主机测评 » PHP2Shell(CVE-2026-109618 / 619)IPS 自定义规则字段级配置指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址