CVE-2019-9641
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 EXIF extension reads the metadata that cameras embed in JPEG and TIFF images, through functions such as exif_read_data().
An Integer Overflow vulnerability (CVE-2019-9641) has been identified in exif_process_IFD_in_TIFF(), part of PHP's EXIF extension, which allows an attacker who supplies a crafted TIFF image to a 32-bit PHP build to bypass its bounds checks, so that PHP parses uninitialized memory and data outside the file as EXIF directory entries. PHP tracks this issue as bug #77509.
Per MITRE CWE-190: The product performs a calculation that can produce an integer overflow or wraparound when the logic assumes that the resulting value will always be larger than the original value. This occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may become a very small or negative number.
This issue affects PHP before 7.1.27, PHP 7.2 before 7.2.16 and PHP 7.3 before 7.3.3, which includes the End-of-Life PHP 5.6 release line through its final release (5.6.40). Only 32-bit builds can reach the flaw.
Details
Module Info
- Product: PHP
- Affected packages:
php-src(ext/exif) - Affected versions: <7.1.27, >=7.2.0 <7.2.16, >=7.3.0 <7.3.3
- GitHub repository: https://github.com/php/php-src
- Published packages: https://www.php.net/downloads
- Package manager: N/A
- Fixed in:
- OSS PHP 7.1.27, 7.2.16, 7.3.3
- NES for PHP 5.6.1 (based on PHP 5.6.40)
Vulnerability Info
This Critical-severity vulnerability is found in the exif extension of PHP before 7.1.27, 7.2 before 7.2.16 and 7.3 before 7.3.3. The CVE record, assigned by MITRE, gives no CVSS score; NVD scores it 9.8 under CVSS 3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H). The End-of-Life PHP 5.6 release line never received the upstream fix.
A TIFF file stores its metadata in image file directories (IFDs), each found at an offset given in the file. Before reading a directory, exif_process_IFD_in_TIFF() checks that the offset and the directory size fit inside the file. In PHP 5.6.40 the first check reads:
if (ImageInfo->FileSize >= dir_offset+2) {
sn = exif_file_sections_add(ImageInfo, M_PSEUDO, 2, NULL);
#ifdef EXIF_DEBUG
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF: filesize(x%04X), IFD dir(x%04X + x%04X)", ImageInfo->FileSize, dir_offset, 2);
#endif
php_stream_seek(ImageInfo->infile, dir_offset, SEEK_SET); /* we do not know the order of sections */
php_stream_read(ImageInfo->infile, (char*)ImageInfo->file.list[sn].data, 2);
num_entries = php_ifd_get16u(ImageInfo->file.list[sn].data, ImageInfo->motorola_intel);The offset comes from the file and is added to a size before the comparison. On a 32-bit build, where size_t is 32 bits wide, an offset close to 4 GiB wraps around when 2 is added, so the check passes. The seek and read then fail because the offset lies past the end of the file, and the parser goes on to decode the uninitialized buffer as a directory entry count. The later checks in the same function, which add the directory size and the IFD size to the offset, can wrap the same way. The reporter showed the effect with an 8-byte file under Valgrind.
Exploitation needs a 32-bit PHP build and an application that reads EXIF data, for example with exif_read_data(), from a TIFF image an attacker supplies. On 64-bit builds the offsets cannot wrap. HeroDevs' analysis notes that NES for PHP 5 ships x86_64 builds only, so its packages were not exposed; the fix is carried so the code matches upstream.
The fix rewrites each check to subtract from the file size instead of adding to the offset, so no sum can wrap:
if (ImageInfo->FileSize >= 2 && ImageInfo->FileSize - 2 >= dir_offset) {Mitigation
The PHP project publishes security fixes only for its supported release lines. PHP 5.6 and 7.0 are End-of-Life and will not receive any public updates to address this issue.
Users of the affected components should apply one of the following mitigations:
- Upgrade to PHP 7.1.27, 7.2.16, 7.3.3, or later.
- Leverage a commercial support partner like HeroDevs (NES for PHP) for post-EOL security support.
Credits
- chamal.desilva (finder)
- Stanislav Malyshev (remediation)