CVE-2024-8926
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
PHP is a general-purpose scripting language used mostly for web development. It runs behind web servers through server APIs such as Apache mod_php and PHP-FPM, and powers content management systems and frameworks such as WordPress, Drupal, Moodle and Laravel. Its CGI binary, php-cgi, runs PHP scripts for web servers through the CGI and FastCGI interfaces, and on Windows ships as php-cgi.exe.
A Command Injection vulnerability (CVE-2024-8926) has been identified in the command-line handling of PHP's CGI binary on Windows, which allows a remote attacker, on systems with certain non-standard Windows code page settings, to pass command-line options to php-cgi.exe through the query string of a request, bypassing the fix for CVE-2024-4577, and so reveal script source code or run arbitrary PHP code on the server. PHP tracks this issue as GHSA-p99j-rfp4-xqvq.
Per MITRE CWE-78: The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
This issue affects all versions of PHP before 8.1.30, PHP 8.2 before 8.2.24 and PHP 8.3 before 8.3.12, including the End-of-Life release lines PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4 and 8.0 through their final releases, in each case on Windows.
Details
Module Info
- Product: PHP
- Affected packages:
php-src(sapi/cgi) - Affected versions: <8.1.30, >=8.2.0 <8.2.24, >=8.3.0 <8.3.12
- GitHub repository: https://github.com/php/php-src
- Published packages: https://www.php.net/downloads
- Package manager: N/A
- Fixed in:
- OSS PHP 8.1.30, 8.2.24, 8.3.12
- NES for PHP 5.6.2 (based on PHP 5.6.40)
- NES for PHP 7.4.1 (based on PHP 7.4.33)
Vulnerability Info
This High-severity vulnerability is found in the CGI binary of PHP before 8.1.30, 8.2 before 8.2.24 and 8.3 before 8.3.12 on Windows. The CVE record does not list the End-of-Life PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4 and 8.0 release lines, but their php-cgi.exe still parses options from the query string without the upstream check, and they never received the upstream fix. The PHP project scores it 8.1 under CVSS 3.1 (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H).
When a web server runs PHP as a CGI program and the query string of a request contains no = sign, the server may pass the query string to php-cgi as command-line arguments. To keep attackers from passing options this way, php-cgi skips its own option parsing when the decoded query string starts with a -. In PHP 7.4.33 the check reads:
if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
/* we've got query string that has no = - apache CGI will pass it to command line */
unsigned char *p;
decoded_query_string = strdup(query_string);
php_url_decode(decoded_query_string, strlen(decoded_query_string));
for (p = (unsigned char *)decoded_query_string; *p && *p <= ' '; p++) {
/* skip all leading spaces */
}
if(*p == '-') {
skip_getopt = 1;
}
free(decoded_query_string);
}On Windows, the command line that php-cgi.exe receives goes through character set conversion and Windows' own argument parsing rules, so the bytes PHP checks are not always the bytes that end up as arguments. CVE-2024-4577 exploited the "Best Fit" conversion of some code pages to slip an option past this check, and its fix was later found incomplete. The advisory for this issue shows that when the Windows ANSI code page is pointed at an OEM code page such as 437 in the registry, a byte such as 0xA8 in the query string becomes a double quote, Windows strips the quotes, and php-cgi.exe reads an option such as -s or -d. The advisory's proof of concept sets allow_url_include and auto_prepend_file this way, which runs PHP code taken from the request body. The reporters note that this code page setup is unusual.
Exploitation needs PHP running as php-cgi.exe on Windows behind a web server that passes the query string as arguments, as in the XAMPP PHP-CGI setup, on a system whose code page settings were changed as described. HeroDevs' analysis found that Linux and other non-Windows builds of php-cgi were never exploitable this way, and the fix leaves their code unchanged. The php CLI binary and php-fpm do not contain the CGI SAPI and are not exposed.
Instead of trying to emulate Windows' conversion and parsing rules, the fix stops php-cgi on Windows from parsing options from the query string whenever it runs in CGI or FastCGI mode. The upstream commit notes that this is a backward compatibility break, accepted because it removes this class of issues. The fixed Windows branch reads:
if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
#ifdef PHP_WIN32
skip_getopt = cgi || fastcgi;
#elseMitigation
The PHP project publishes security fixes only for its supported release lines. PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4 and 8.0 are End-of-Life and will not receive any public updates to address this issue.
Until an upgrade is possible, do not run PHP on Windows as php-cgi.exe behind a web server that passes query strings as command-line arguments; the php CLI binary and php-fpm do not contain the affected code.
Users of the affected components should apply one of the following mitigations:
- Upgrade to PHP 8.1.30, 8.2.24, 8.3.12, or later.
- Leverage a commercial support partner like HeroDevs (NES for PHP) for post-EOL security support.
Credits
- MortalAndTry (finder)
- HuanGMz (finder)
- s0duku (finder)
- m4yfly (finder)
- Nora Dossche (remediation)