CVE-2024-5585
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 proc_open() function starts a process and, since PHP 7.4, accepts the command as an array of program name and arguments, which PHP is meant to pass on without shell interpretation.
A Command Injection vulnerability (CVE-2024-5585) has been identified in the Windows implementation of PHP's proc_open() function, which allows an attacker who controls the arguments of a batch file launched with the array syntax to run arbitrary commands, when the program name ends in a space or a dot. The issue bypasses the fix for CVE-2024-1874. PHP tracks this issue as GHSA-9fcc-425m-g385.
Per OWASP: Command injection is an attack in which the goal is execution of arbitrary commands on the host operating system via a vulnerable application. Command injection attacks are possible when an application passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell. In this attack, the attacker-supplied operating system commands are usually executed with the privileges of the vulnerable application.
This issue affects PHP on Windows: PHP 7.4.0 and later before 8.1.29, PHP 8.2 before 8.2.20 and PHP 8.3 before 8.3.8, which includes the End-of-Life PHP 7.4 and 8.0 release lines through their final releases (7.4.33 and 8.0.30).
Details
Module Info
- Product: PHP
- Affected packages:
php-src(ext/standard) - Affected versions: >=7.4.0 <8.1.29, >=8.2.0 <8.2.20, >=8.3.0 <8.3.8 (Windows only)
- 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.29, 8.2.20, 8.3.8
- NES for PHP 7.4.1 (based on PHP 7.4.33)
Vulnerability Info
This High-severity vulnerability is found in the Windows builds of PHP 7.4.0 and later before 8.1.29, 8.2 before 8.2.20 and 8.3 before 8.3.8, including the End-of-Life PHP 7.4 and 8.0 release lines, which never received the upstream fix. The PHP project scores it 7.7 under CVSS 3.1 (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L).
On Windows, a .bat or .cmd file always runs through cmd.exe, which interprets characters such as &, | and % in its arguments. CVE-2024-1874 showed that proc_open() did not escape arguments for cmd.exe in that case. Its fix added a check that decides whether the program will run through cmd.exe by looking at the extension of the program name, and escapes the arguments only then. In PHP 8.1.28 the check ends with:
if (extension == NULL || extension == prog_name) {
/* No file extension found, it is not batch file. */
return false;
}
/* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */
return _stricmp(extension, ".bat") == 0 || _stricmp(extension, ".cmd") == 0;Windows strips trailing spaces and dots from a program name before it starts the program, so x.bat followed by a space, or x.bat., still runs the batch file through cmd.exe, but the string comparison no longer sees a .bat or .cmd extension. The arguments are then passed without the extra escaping, and an attacker who controls them can inject commands that cmd.exe runs with the privileges of the PHP process. On PHP 7.4, which never received the CVE-2024-1874 fix upstream, the arguments of batch files are not escaped for cmd.exe at all.
Exploitation needs a Windows build of PHP and an application that launches a batch file through proc_open() with the array syntax, passes attacker-controlled arguments, and lets the program name end in a space or a dot. Linux and other Unix builds are not affected, because there proc_open() hands the argument array directly to execvp() without a shell and all of the changed code is Windows-only. HeroDevs' release notes for NES for PHP 7.4.1 state that this fix is carried for Windows builds.
The fix resolves the program name the way Windows does, with GetLongPathNameW() and GetFullPathNameW(), before it checks the extension, so trailing spaces and dots no longer hide a batch file:
bool uses_cmd = false;
if (_wcsicmp(file_part, L"cmd.exe") == 0 || _wcsicmp(file_part, L"cmd") == 0) {
uses_cmd = true;
} else {
const WCHAR *extension_dot = wcsrchr(file_part, L'.');
if (extension_dot && (_wcsicmp(extension_dot, L".bat") == 0 || _wcsicmp(extension_dot, L".cmd") == 0)) {
uses_cmd = true;
}
}Mitigation
The PHP project publishes security fixes only for its supported release lines. PHP 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 launch batch files through proc_open() with arguments derived from user input on Windows, and do not let user input influence the program name.
Users of the affected components should apply one of the following mitigations:
- Upgrade to PHP 8.1.29, 8.2.20, 8.3.8, or later.
- Leverage a commercial support partner like HeroDevs (NES for PHP) for post-EOL security support.
Credits
- tianstcht (finder)
- Nora Dossche (remediation)