针对 PHP2Shell(CVE-2026-109618 / CVE-2026-109619)的 Defender XDR 暴露面狩猎。
v3.3 · 2026 年 10 月 22 日
目的: 查找已载入的、正在运行 PHP 且可能暴露于 PHP2Shell 的设备。
范围: Defender XDR 高级狩猎 · 已载入的 Windows 和 Linux 端点 · 默认回溯 30 天 · 仅限活跃的 PHP。不覆盖:休眠安装和未托管设备。无法在 Sentinel 中运行,因为已安装软件(TVM)表只能在 Defender XDR 中查询。
| 狩猎 | Windows | Linux | 问题 |
|---|---|---|---|
| 1 | windows/01-any-php.kql | linux/01-any-php.kql | 是否存在任何 PHP?按设备给出是/否。 |
| 2 | windows/02-evidence-breakout.kql | linux/02-evidence-breakout.kql | 带版本信息的证据明细。 |
| 3 | windows/03-safety-net.kql | linux/03-safety-net.kql | 安全网:在 Web 端口上提供服务的设备、监听进程以及 PHP 状态。 |
所有事件检查都使用同一个回溯窗口,即每个狩猎查询顶部的 let Lookback = 30d;。IP 地址来自最近 7 天内每个适配器的最新报告。已安装软件为当前 TVM 快照。仅检查已载入的端点(OnboardingStatus == "Onboarded"、DeviceCategory == "Endpoint")。
只要满足以下任意一项,该设备即被视为已发现 PHP。
名称匹配方式:
^…$),因此必须匹配整个文件名,绝不能只匹配其中一部分。startswith "php",两个操作系统上还加上 frankenphp,Linux 上还加上 lsphp。随后正则表达式只对剩余项运行。php9.dll)会自动匹配。patterns.test.js 会用这些示例运行每个正则表达式。如果你修改了某个正则表达式,请同步更新其中的示例。Windows
| 检查项 | 表 | 匹配 | 重要性 |
|---|---|---|---|
| 已启动的 PHP 可执行文件 | DeviceProcessEvents | 正则 ^(php(-cgi|-win)?|frankenphp)\.exe$,仅允许四个名称:php.exe(CLI)、php-cgi.exe(FastCGI 工作进程)、php-win.exe(CLI,无控制台)、frankenphp.exe(嵌入 Web 服务器的 PHP)。phpstorm64.exe 及其他 php* 工具不匹配 | 证明 PHP 曾运行。狩猎 2 会从二进制文件的版本信息(ProcessVersionInfoProductVersion)中显示版本 |
| 已加载的 PHP 引擎 DLL | DeviceImageLoadEvents | 正则 ^php\d*(ts|isapi|apache[\w_]*)?\.dll$:php、任意版本号、可选的 ts / isapi / apache… 后缀,然后是 .dll。示例见下方 DLL 表。扩展 DLL(php_curl.dll 及其他 php_*.dll)不匹配,因为 php 之后不允许直接跟下划线 | 这是查看 PHP 在其他进程(如 IIS 或 Apache)内部运行的唯一方式,此时不会有 php*.exe 启动。狩猎 2 会显示该 DLL 以及加载它的进程 |
| 已安装软件 | DeviceTvmSoftwareInventory | 不是正则:SoftwareName has "php"(名称中 php 作为完整单词)或 SoftwareVendor =~ "php"(精确匹配,不区分大小写) | 捕获已注册的安装。Zip 安装(Windows 上常用的方式)通常不会注册 |
Windows 模式所匹配的 PHP 引擎 DLL 示例
| DLL | 说明 | 典型宿主进程(在 hunt 2 中显示) |
|---|---|---|
php8.dll、php7.dll | 引擎,非线程安全构建 | php-cgi.exe(IIS、nginx 或 Apache mod_fcgid 下的 FastCGI)、php.exe |
php8ts.dll、php7ts.dll、php5ts.dll | 引擎,线程安全构建 | httpd.exe(Apache 模块)、php.exe |
php8apache2_4.dll、php7apache2_4.dll、php5apache2_2.dll | Apache 模块加载器 | httpd.exe |
php5isapi.dll | 旧版 IIS ISAPI 模块(PHP 5.2 及更早版本,已不受支持) | w3wp.exe |
该表列出的是常见名称,而非允许列表:任何符合该模式的名称都会匹配。DLL 名称只给出主版本号。确切版本来自同一设备上的 php-cgi.exe 或 php.exe 进程行,或来自已安装的软件。
Linux
| 检查项 | 表 | 匹配 | 重要性 |
|---|---|---|---|
| PHP 二进制文件已启动 | DeviceProcessEvents | 正则 ^(php[\d.]*|php-(fpm|cgi)[\d.]*|lsphp[\d.]*|frankenphp)$:php、php-fpm、php-cgi 或 lsphp(LiteSpeed),每个都可带由数字和点组成的可选版本号,外加 frankenphp。示例:php、php8.3、php83、php-fpm8.3、php-cgi8.2、lsphp83。phpunit、phpize 和 php-config 等工具不会匹配,因为基础名称之后只允许出现数字和点 | 证明 PHP 曾运行。Hunt 2 显示一个 major.minor 提示,由第二个正则 php-?(?:fpm|cgi)?/?(\d+\.\d+) 从名称、路径或命令行中提取(例如 php-fpm8.3 或 /etc/php/8.3/ 给出 8.3.x) |
| 已安装的软件包 | DeviceTvmSoftwareInventory | 不是正则:SoftwareName contains "php"(子串匹配,因此 php8.3-fpm 和 libapache2-mod-php8.3 等带版本号的名称也会匹配)或 SoftwareVendor =~ "php" | 这是针对 Apache mod_php 以及自窗口开始之前就一直在运行的 php-fpm 的唯一检查:Linux 在此没有库加载检查,而 fork 出的 php-fpm 工作进程不会产生进程启动事件 |
| 检查项 | 表 | 匹配 | 重要性 |
|---|---|---|---|
| 活跃的 Web 服务 | DeviceNetworkEvents | 在固定端口列表上的 InboundConnectionAccepted:80、443、8080、8443。排除回环(RemoteIPType != "Loopback")。显示去重后的来源和公网来源,以及接受连接的进程(via <process>) | 证明设备正在提供服务,即使其 Web 服务器在回溯窗口之前就已启动。ntoskrnl.exe = HTTP.sys(IIS、ADFS、RD Gateway、Windows Admin Center、SSTP) |
| Web 服务器已启动 | DeviceProcessEvents | 不是正则:固定精确名称列表,不区分大小写(in~)。Windows:w3wp.exe、httpd.exe、nginx.exe、caddy.exe、lighttpd.exe、frankenphp.exe。Linux:httpd、apache2、nginx、lshttpd、litespeed、openlitespeed、caddy、lighttpd、frankenphp | 在窗口内启动且未加载 PHP 的 Web 服务器会以高置信度给出“未发现”。Windows 还会显示 IIS 应用程序池名称,由正则 -ap\s+"?([^"\s]+) 从 w3wp.exe 命令行中提取 |
hunt 3 中的 PHP 列取值
| 取值 | 含义 |
|---|---|
PHP seen (see hunt 2) | 至少有一项 PHP 检测检查匹配。 |
Not seen | 没有 PHP 证据,并且要么在窗口内有 Web 服务器启动(高置信度),要么该设备未提供 Web 服务。 |
Not seen - no web server start in <N>d(N = Lookback) | 正在 Web 端口上提供服务,但没有可检查的 Web 服务器进程启动。这是残余盲区:请在主机上检查 via 进程。 |
uncomment for evidence-only rows 的那一行。let Lookback = 30d;,并在所有狩猎中使用相同的值。
npm test 会拒绝超过 30d 的值以及各狩猎之间不一致的值。两种操作系统:
Windows:
Linux,在 Linux 阳性对照测试通过之前未经验证:
Linux 覆盖缺口:
PHP 检测块在每个操作系统的三个狩猎中完全相同。请一起修改这三处;如果它们出现偏差,npm test 会失败。当你更改检测正则表达式时,请更新 tests/lint/patterns.test.js 中的预期匹配和非匹配项。测试从查询中读取正则表达式,因此它检查的是你的修改,而不是副本。
cd tests/lint && npm install && npm test。这会运行:
schema.json,对两种全行模式和仅证据模式下的每个狩猎进行检查。docs/positive-control-test-windows.md 和 docs/positive-control-test-linux.md。离线检查证明的是语法、列名、一致性和名称匹配,而非结果。只有阳性对照测试才能证明检测有效。
let Lookback = 30d;),而不是在每个检查中硬编码。readme-sync.test.js 对照查询进行检查。lookback.test.js 强制每个狩猎只有一个定义、各狩猎使用相同的值,且最大为 30d。queries/windows/ 和 queries/linux/。via <process>);ntoskrnl.exe = HTTP.sys。