CVE-2024-1874

Command Injection
Affects
PHP
in
PHP
No items found.
Versions
>=7.4.0 <=8.0.30, >=8.1.0 <8.1.28, >=8.2.0 <8.2.18, >=8.3.0 <8.3.5 (Windows only)

Patch Available.

Exclamation circle icon
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 external programs, and since PHP 7.4 accepts the command as an array of program name and arguments, which PHP documents as running the program without a shell.

A Command Injection vulnerability (CVE-2024-1874) has been identified in the Windows implementation of proc_open(), which allows an attacker who controls an argument passed to a .bat or .cmd file through the array form of proc_open() to run arbitrary commands on the server, even when the bypass_shell option is set. PHP tracks this issue as GHSA-pc52-254m-w9w7.

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. Command injection attacks are possible largely due to insufficient input validation.

This issue affects PHP on Windows: PHP 8.1 before 8.1.28, PHP 8.2 before 8.2.18 and PHP 8.3 before 8.3.5, as well as the End-of-Life release lines PHP 7.4 and 8.0 through their final releases (7.4.33 and 8.0.30).

Details

Module Info

Vulnerability Info

This Critical-severity vulnerability is found in the Windows builds of PHP 8.1 before 8.1.28, 8.2 before 8.2.18 and 8.3 before 8.3.5, and of the End-of-Life PHP 7.4 and 8.0 release lines, which never received the upstream fix. The PHP project scores it 9.4 under CVSS 3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L).

When proc_open() receives the command as an array on Windows, PHP builds a single command line from the elements and passes it to CreateProcess without a shell. Each argument is quoted and escaped following the rules of the Microsoft C runtime, which uses the backslash as its escape character. According to the advisory, Windows implicitly starts cmd.exe to run a .bat or .cmd file, so the arguments are then parsed by cmd.exe as well, and "command prompts will not recognize \ as the escape character". An argument containing a double quote can therefore end the quoted string as far as cmd.exe is concerned, and characters such as & that follow it are treated as command separators.

An application that calls a batch file through proc_open() with an array command and includes attacker-controlled data in its arguments can therefore be made to run arbitrary commands with the privileges of the PHP process. The advisory notes that this happens with or without the bypass_shell option, which makes the behavior unexpected for developers who chose the array form to avoid shell interpretation. HeroDevs' analysis notes that every changed line is Windows-specific: on Linux and other POSIX systems proc_open() passes the argument array directly to execvp() without a shell, so non-Windows servers are not exposed.

The fix detects when the program will be run by cmd.exe (a .bat or .cmd file, or cmd.exe itself) and, for arguments that contain characters special to cmd.exe, escapes the surrounding quotes and those characters with ^:

if (is_cmd_argument) {
    has_special_character = is_special_character_present(arg);
    if (has_special_character) {
        /* Escape double quote with ^ if executed by cmd.exe. */
        smart_str_appendc(str, '^');
    }
}
smart_str_appendc(str, '"');

The program name is checked once, and every following argument is escaped accordingly:

if (is_prog_name) {
    is_cmd_execution = is_executed_by_cmd(ZSTR_VAL(arg_str));
} else {
    smart_str_appendc(&str, ' ');
}

append_win_escaped_arg(&str, arg_str, !is_prog_name && is_cmd_execution);

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 pass untrusted data as arguments to .bat or .cmd files through proc_open() on Windows, or reject arguments that contain double quotes or characters special to cmd.exe.

Users of the affected components should apply one of the following mitigations:

  • Upgrade to PHP 8.1.28, 8.2.18, 8.3.5, or later.
  • Leverage a commercial support partner like HeroDevs (NES for PHP) for post-EOL security support.

Credits

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Critical
ID
CVE-2024-1874
PROJECT Affected
PHP
Versions Affected
>=7.4.0 <=8.0.30, >=8.1.0 <8.1.28, >=8.2.0 <8.2.18, >=8.3.0 <8.3.5 (Windows only)
NES Versions Affected
Published date
April 29, 2024
≈ Fix date
April 11, 2024
Fixed in
Category
Command Injection
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
PHP
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.