跳转到帖子

Windows PHP-CGI 参数注入漏洞 CVE-2024-4577 验证、日志取证与修复

精选回复

发布于

背景

CVE-2024-4577 是 Windows 环境下 PHP-CGI 的参数注入漏洞,主要影响以 CGI 模式运行 PHP 的部署。其根因与 Windows 部分代码页的 Best-Fit 字符转换有关:请求中的软连字符字节可能在转换后变成普通连字符,使 PHP-CGI 将原本不应被识别的输入解析为命令行参数。

该问题不是普通 PHP 业务代码漏洞。只有 Windows、PHP-CGI 暴露方式、系统代码页及 Web 服务器映射等条件同时满足时,才可能形成远程代码执行。验证必须在已授权环境进行,并优先使用固定字符串响应,避免执行系统命令或写入文件。

影响条件

检查项风险条件排查方式
操作系统Windows查看主机资产或执行 systeminfo
PHP 运行模式CGI/FastCGI,且 php-cgi.exe 可被调用检查 IIS、Apache 配置及进程命令行
PHP 版本低于官方修复版本执行 php-cgi.exe -v
代码页繁体中文、简体中文、日文等受影响代码页风险较高执行 chcp,并结合区域设置确认
入口暴露存在 CGI 映射或可访问的 php-cgi.exe 路径检查 ScriptAlias、Action、Handler Mapping

首批修复版本包括 PHP 8.1.29、8.2.20、8.3.8。更老且已结束维护的 PHP 分支不应只做局部缓解,建议直接迁移到当前受支持版本,并以 PHP 官方安全公告中的最新版本为准。

问题定位

先确认运行模式,不要仅依据响应头中的 PHP 版本作判断。IIS FastCGI、Apache mod_fcgid、Apache Action 映射的配置位置不同,应同时检查服务配置和实际进程。

REM 查看 PHP-CGI 版本与系统代码页
C:\php\php-cgi.exe -v
chcp

REM 查找正在运行的 CGI 进程及命令行
wmic process where "name='php-cgi.exe'" get ProcessId,ParentProcessId,CommandLine

REM Apache 配置中检索 CGI 映射
findstr /S /I /N "ScriptAlias Action SetHandler php-cgi.exe mod_fcgid" C:\Apache24\conf\*.conf

REM IIS 导出处理程序映射
%windir%\system32\inetsrv\appcmd.exe list config /section:system.webServer/handlers

重点关注 Apache 中将 .php 交给 php-cgi.exe 的 Action、ScriptAlias 或 ExecCGI 配置,以及 IIS Handler Mapping 中指向 php-cgi.exe 的映射。如果 php-cgi.exe 所在目录被当作普通静态目录发布,也应视为高风险配置错误。

技术分析

PHP-CGI 会处理命令行形式的配置参数。正常情况下,PHP 对以连字符开头的查询字符串有防护;但在受影响的 Windows 代码页中,特定字节经过 Best-Fit 转换后可能变成连字符,从而绕过检查。攻击者随后可能注入 allow_url_include、auto_prepend_file 等运行时配置,使请求体在目标 PHP 进程启动阶段被解释。

漏洞是否可利用取决于 Web 服务器如何拼接 CGI 参数、请求路径是否到达 PHP-CGI,以及转换发生时使用的代码页。因此,仅扫描版本会产生误报;仅验证某个固定路径又可能漏报。准确结论应由版本、配置和受控动态验证三部分共同支撑。

授权验证步骤

以下请求仅输出固定标记,不执行系统命令、不落盘。应先在隔离测试环境复现,再对生产目标进行最小化验证。将 URL 替换为实际已确认的 PHP-CGI 映射入口;不同部署不一定存在示例路径。

curl -i --path-as-is -X POST ^
  " ^
  -H "Content-Type: application/x-www-form-urlencoded" ^
  --data-binary "<?php header('Content-Type: text/plain'); echo 'CVE-2024-4577-CHECK'; exit; ?>"

判断标准如下:

  • 响应正文出现唯一标记 CVE-2024-4577-CHECK,说明请求体被 PHP 解释,动态验证成立。
  • 返回 404 只能说明该路径不存在,不能据此判定不受影响。
  • 返回 403 可能是 WAF 或 Web 服务器规则拦截,仍需核对 PHP 版本和 CGI 映射。
  • 返回 PHP 源码、下载响应或 500 错误时,应结合错误日志判断处理链路,避免重复发送探测请求。
不要将验证载荷替换为 system、shell_exec、下载器或持久化代码。固定标记已经足以证明参数注入与代码解释能力。

日志留痕与取证

优先保全原始访问日志,不要先做字符串替换或日志清洗。检索时同时关注原始编码、大小写变化及解码后的参数名。典型线索包括 %AD、allow_url_include、auto_prepend_file、php://input,以及直接访问 php-cgi.exe 的请求。

REM Apache 日志快速检索
findstr /S /I /N /C:"%AD" /C:"allow_url_include" /C:"auto_prepend_file" /C:"php-cgi.exe" C:\Apache24\logs\*.log

REM IIS 日志检索
findstr /S /I /N /C:"%AD" /C:"allow_url_include" /C:"auto_prepend_file" /C:"php-cgi.exe" C:\inetpub\logs\LogFiles\*.log

REM PowerShell 检查近期新增或修改的 PHP 文件
Get-ChildItem C:\inetpub\wwwroot -Recurse -File -Include *.php |
  Where-Object LastWriteTime -gt (Get-Date).AddDays(-7) |
  Select-Object FullName,Length,CreationTime,LastWriteTime

REM 检查 php-cgi.exe 是否派生异常子进程
Get-CimInstance Win32_Process |
  Where-Object {$_.Name -match 'cmd.exe|powershell.exe|certutil.exe|bitsadmin.exe'} |
  Select-Object Name,ProcessId,ParentProcessId,CommandLine

IIS 的 cs-uri-query 字段可能记录查询字符串,但不同日志配置可能截断、解码或遗漏内容。还应关联 WAF、反向代理、EDR 和 Windows 进程审计日志。若已启用安全日志中的进程创建事件,可重点检查事件 ID 4688;Sysmon 环境则检查事件 ID 1,并确认父进程是否为 php-cgi.exe、httpd.exe 或 w3wp.exe。

发现可疑请求后,应围绕同一源地址、相邻时间窗口和相同 User-Agent 扩展查询,同时检查 Web 根目录、临时目录、计划任务、服务项及账户变更。单纯删除可疑 PHP 文件不足以完成处置。

修复与缓解建议

  • 升级到 PHP 官方当前受支持的安全版本。至少跨过 8.1.29、8.2.20、8.3.8 对应修复线,升级后重新执行版本与配置核验。
  • 不再维护的 PHP 5.x、7.x 和旧 8.x 分支应迁移,不建议继续依赖 WAF 规则维持运行。
  • 移除外部可访问的 php-cgi.exe 路径,不要将 PHP 安装目录发布为 Web 目录。
  • 复核 Apache ScriptAlias、Action、AddHandler、SetHandler、ExecCGI,以及 IIS Handler Mapping,仅保留业务必需映射。
  • 如业务允许,改用更清晰的 FastCGI 部署边界,并限制 Web 服务账户权限,禁止其写入程序目录和系统目录。
  • 在反向代理或 WAF 中拦截针对 CGI 参数的异常编码可作为临时措施,但不能替代升级。规则应同时覆盖原始 URI 和规范化 URI,并验证不会被多次解码绕过。
  • 修复后重启相关 PHP-CGI、Apache 或 IIS 进程,避免旧进程继续加载旧二进制,并再次执行固定标记验证。

修复确认

修复验收至少包含四项:PHP 二进制版本已更新;CGI 映射符合最小暴露原则;原验证请求不再返回固定标记;日志与 EDR 中未出现 php-cgi.exe 派生脚本解释器或系统工具的异常链路。若历史日志已经出现成功利用特征,应按入侵事件处理,而不是在升级后直接关闭工单。

总结

CVE-2024-4577 的排查不能停留在版本扫描。可靠流程是先确认 Windows 与 PHP-CGI 部署条件,再检查处理程序映射和代码页,最后使用无副作用标记完成授权验证。处置时既要升级 PHP,也要收敛 CGI 暴露面,并通过访问日志、进程审计和文件时间线判断漏洞是否已被利用。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
漏洞验证与修复流程示意图
漏洞成因、验证条件与修复闭环示意

这个漏洞的排查重点不应只放在“能否复现”,还要同时确认部署方式、原始请求参数和 php-cgi.exe 的后续进程行为。CVE-2024-4577 主要影响 Windows 下以 CGI 模式运行 PHP 的场景,尤其与 Windows 字符集的 best-fit 转换有关;仅凭服务器安装了 PHP,不能直接判断存在风险。

1. 先确认是否处于受影响链路

检查 PHP 版本和 SAPI:

php -v
php -i | findstr /I "Server API"
where php
where php-cgi

重点查 Web 服务配置中是否把请求交给 php-cgi.exe,例如 Apache 的 Action、ScriptAlias、SetHandler,或者 IIS 的 Handler Mapping:

findstr /S /I /N "php-cgi.exe ScriptAlias Action SetHandler" C:\Apache24\conf\*.conf C:\Apache24\conf\extra\*.conf
%windir%\system32\inetsrv\appcmd list config /section:system.webServer/handlers

如果使用的是 PHP-FPM、Apache module,或者 PHP 根本不在 Windows 上运行,通常不属于该漏洞的直接利用路径,但仍应核实反向代理后端的实际部署。

2. 版本修复

应至少升级到已修复版本:PHP 8.1.29、8.2.20、8.3.8;更老且已停止维护的分支不要继续通过规则“续命”,建议直接迁移到当前受支持版本。升级后注意确认 Web 服务实际加载的是新目录中的二进制,而不是只更新了命令行环境变量:

where php
(Get-Command php).Source
(Get-Item "C:\path\to\php-cgi.exe").VersionInfo | Format-List FileVersion,ProductVersion

修改后重启对应服务,再通过 Web 页面输出的 PHP_VERSION 和 PHP_SAPI 复核,避免 CLI 与 Web 使用不同版本。

3. 日志取证建议

访问日志中建议同时搜索编码后的软连字符字节、PHP 命令行参数特征,以及重复编码形式。不要只搜索明文 -d,因为代理、WAF 和 Web 服务记录 URL 的解码阶段可能不同。

PowerShell 可先做一轮粗筛:

$patterns = '%AD','%ad','%25AD','%25ad','-d','auto_prepend_file',
            'allow_url_include','php://input','php://filter'

Get-ChildItem C:\inetpub\logs\LogFiles,C:\Apache24\logs -Recurse -File -ErrorAction SilentlyContinue |
  Select-String -SimpleMatch -Pattern $patterns |
  Select-Object Path,LineNumber,Line

IIS W3C 日志重点看 date、time、c-ip、cs-uri-stem、cs-uri-query、sc-status、sc-bytes 和 time-taken。如果日志字段没有记录查询字符串,需结合反向代理、WAF、负载均衡器或流量留存补齐证据。Apache 则确认 LogFormat 中使用了 %r 或 %q,否则可能无法还原参数。

命中可疑请求后,不要仅以 HTTP 200 判断利用成功。更关键的是检查同一时间窗口内是否出现由 php-cgi.exe 派生的命令解释器、下载工具或脚本宿主:

$start = (Get-Date).AddDays(-7)

Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4688; StartTime=$start} |
  Where-Object {
    $_.Message -match 'php-cgi\.exe|cmd\.exe|powershell\.exe|pwsh\.exe|certutil\.exe|bitsadmin\.exe|mshta\.exe|rundll32\.exe'
  } |
  Select-Object TimeCreated,Id,Message

如果部署了 Sysmon,优先查 Event ID 1,并关联 ParentImage 为 php-cgi.exe 的事件:

Get-WinEvent -FilterHashtable @{
  LogName='Microsoft-Windows-Sysmon/Operational'
  Id=1
  StartTime=(Get-Date).AddDays(-7)
} | Where-Object {
  $_.Message -match 'ParentImage:.*\\php-cgi\.exe'
} | Select-Object TimeCreated,Message

还应检查 PowerShell 4104、计划任务、服务创建及常见落地目录:

Get-WinEvent -FilterHashtable @{
  LogName='Microsoft-Windows-PowerShell/Operational'
  Id=4104
  StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue

schtasks /query /fo LIST /v
sc.exe query type= service state= all

Get-ChildItem C:\Windows\Temp,$env:TEMP,C:\inetpub\wwwroot -Recurse -File -ErrorAction SilentlyContinue |
  Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
  Sort-Object LastWriteTime -Descending |
  Select-Object LastWriteTime,Length,FullName

如果已经发现异常子进程或文件落地,应按失陷主机处理:先隔离网络,保存 IIS/Apache、Security、Sysmon、PowerShell 日志和可疑文件哈希,再进行清理。只删除 WebShell 或升级 PHP,不能排除凭据、计划任务和服务已被持久化。

4. 临时缓解不能代替升级

在无法立即升级时,可以暂时下线 CGI 映射,限制外部访问,或在最前端按原始请求目标拦截相关编码和异常参数。但需要注意:不同组件对 URL 的解码次数不同,单纯针对已解码参数写规则可能被双重编码绕过。因此规则应部署在最靠前、能够检查 raw URI 的位置,并同时记录命中日志。

长期方案仍是升级 PHP,并尽量避免在 Windows 上使用传统 CGI 映射。修复完成后建议保留一段时间的检测规则,重点告警“外部请求命中 PHP CGI 参数特征”以及“Web/PHP 进程派生命令解释器”这两类事件,后者对判断是否已执行成功更有价值。

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。