CVE-2023-3824

Stack-based Buffer Overflow
Affects
PHP
in
PHP
No items found.
Versions
<8.0.30, >=8.1.0 <8.1.22, >=8.2.0 <8.2.8

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 Phar extension, built by default, reads PHP archives as well as tar and zip archives, and its phar:// stream wrapper lets scripts open files and list directories inside them.

A Buffer Overflow vulnerability (CVE-2023-3824) has been identified in the phar_dir_read() function of PHP's Phar extension, which allows an attacker who supplies a phar archive with a very long entry name to overwrite memory on the stack, and to make PHP read past the end of a name, when an application lists a directory inside that archive. PHP tracks this issue as GHSA-jqcx-ccgc-xwhv.

Per MITRE CWE-121: A stack-based buffer overflow condition is a condition where the buffer being overwritten is allocated on the stack (i.e., is a local variable or, rarely, a parameter to a function).

This issue affects PHP before 8.0.30, PHP 8.1 before 8.1.22 and PHP 8.2 before 8.2.8, which includes every End-of-Life release line from PHP 5.6 through 7.4, each through its final release.

Details

Module Info

Vulnerability Info

This Critical-severity vulnerability is found in the Phar extension of PHP before 8.0.30, 8.1 before 8.1.22 and 8.2 before 8.2.8, including every End-of-Life release line from PHP 5.6 through 7.4, 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 a script lists a directory inside a phar:// archive, for example with opendir() and readdir(), scandir() or DirectoryIterator, the Phar extension builds a list of entry names and phar_dir_read() copies each one into a php_stream_dirent record supplied by the caller. That record holds the name in a fixed buffer of MAXPATHLEN bytes. In PHP 7.4.33 the copy reads:

zend_hash_move_forward(data);
to_read = MIN(ZSTR_LEN(str_key), count);

if (to_read == 0 || count < ZSTR_LEN(str_key)) {
    return 0;
}

memset(buf, 0, sizeof(php_stream_dirent));
memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read);
((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';

The length check compares the name against the size of the whole record rather than leaving room for a terminator, and the terminator is written one byte too far, at to_read + 1 instead of to_read. A name of MAXPATHLEN - 1 bytes or more therefore writes past the end of the buffer. The record is usually a local variable of the calling function, so the write lands on the stack, which may lead to memory corruption or code execution. A name of exactly MAXPATHLEN bytes also leaves the buffer without any terminator, so readdir() can read past it and return adjacent memory.

Exploitation needs an application that lists a directory inside a phar:// archive that the attacker supplied, under any SAPI with the Phar extension enabled, which is the default. The phar.readonly setting does not prevent this, because the archive is only read. HeroDevs' analysis found the same code path in the PHP 5.6, 7.2 and 7.4 lines. Applications that never open archives from untrusted sources through phar:// are not exposed.

The fix accepts only a record of the expected size, skips names that do not fit with room for a terminator, and copies with PHP_STRLCPY(), which always terminates the string:

php_stream_dirent *dirent = (php_stream_dirent *) buf;

if (sizeof(dirent->d_name) <= ZSTR_LEN(str_key)) {
    return 0;
}

memset(dirent, 0, sizeof(php_stream_dirent));
PHP_STRLCPY(dirent->d_name, ZSTR_VAL(str_key), sizeof(dirent->d_name), ZSTR_LEN(str_key));

Mitigation

The PHP project publishes security fixes only for its supported release lines. PHP 5.6, 7.0, 7.1, 7.2, 7.3 and 7.4 are End-of-Life and will not receive any public updates to address this issue.

Until an upgrade is possible, do not open or list archives from untrusted sources through the phar:// wrapper, or disable the Phar extension if the application does not need it.

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

  • Upgrade to PHP 8.0.30, 8.1.22, 8.2.8, 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-2023-3824
PROJECT Affected
PHP
Versions Affected
<8.0.30, >=8.1.0 <8.1.22, >=8.2.0 <8.2.8
NES Versions Affected
Published date
August 11, 2023
≈ Fix date
August 3, 2023
Fixed in
Category
Stack-based Buffer Overflow
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.