Описание
Buffer overflow and overread in phar_dir_read()
Summary
Buffer mismanagement in phar_dir_read()
causes a buffer overflow and a buffer overread later.
Details
There are few issues here:
-
The if check
to_read == 0 || count < ZSTR_LEN(str_key)
is not right. In particular, if this is false we know thatcount >= ZSTR_LEN(str_key)
. Furthermore, because ofto_read = MIN(ZSTR_LEN(str_key), count);
we now actually have:to_read == ZSTR_LEN(str_key)
. If we have a filename length (i.e.ZSTR_LEN(str_key)
) equal tosizeof(php_stream_dirent)
, then we getZSTR_LEN(str_key) == count == to_read == sizeof(php_stream_dirent)
.Take a look now at this line:
((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
. Assumesizeof(php_stream_dirent)
is 4096 like on most Linuxes. Then we write at offset 4097, which is two bytes outside ofbuf
. This line was actually supposed to useto_read
instead ofto_read + 1
, because now even if it doesn't overflow, it does not properly NUL-terminate the filename. We're just lucky there's a memset above. Correcting that to useto_read
doesn't solve the whole problem: it would still overflow because it will write at offset 4096 which is still outsidebuf
.This means we have a stack information leak and a buffer write overflow.
-
Both the
memset
and the return value assume thatcount == sizeof(php_stream_dirent)
. In principle if there are any callers where that count is smaller, a buffer overflow occurs in thememset
. However, inside PHP itself I did not find any such caller, but this may be a concern for third-party extensions.
PoC
I created a reproducer using PHP-8.0 with these configure flags: ./configure --enable-debug --disable-all --enable-phar --with-valgrind
using compiler gcc (GCC) 13.1.1 20230429
.
Create the malicious Phar file using:
Trigger the buffer overflow and overread using this script:
If you run this in Valgrind, i.e. valgrind ./sapi/cli/php trigger.php
you'll find two Valgrind complaints:
The first complaint is because the strlen() function overreads the d_name buffer because it isn't properly NUL-terminated. The second one is because it writes the name using var_dump, and the name contains (uninitialized) stack data. Valgrind won't complain about the stack buffer write overflow, but you can inspect the memory using gdb for example that a piece of the stack gets overwritten.
Impact
Exploiting this is difficult to do and heavily depends on the application you're targetting, but possible in theory I think using a combination of stack info leaks and buffer write overflows. People who inspect contents of untrusted phar files could be affected.
Пакеты
< 8.0.30
8.0.30
EPSS
9.4 Critical
CVSS3
CVE ID
Дефекты
Связанные уязвимости
In PHP version 8.0.* before 8.0.30, 8.1.* before 8.1.22, and 8.2.* before 8.2.8, when loading phar file, while reading PHAR directory entries, insufficient length checking may lead to a stack buffer overflow, leading potentially to memory corruption or RCE.
In PHP version 8.0.* before 8.0.30, 8.1.* before 8.1.22, and 8.2.* before 8.2.8, when loading phar file, while reading PHAR directory entries, insufficient length checking may lead to a stack buffer overflow, leading potentially to memory corruption or RCE.
In PHP version 8.0.* before 8.0.30, 8.1.* before 8.1.22, and 8.2.* before 8.2.8, when loading phar file, while reading PHAR directory entries, insufficient length checking may lead to a stack buffer overflow, leading potentially to memory corruption or RCE.
In PHP version 8.0.* before 8.0.30, 8.1.* before 8.1.22, and 8.2.* bef ...
Уязвимость функции phar_dir_read() интерпретатора PHP, позволяющая нарушителю выполнить произвольный код
EPSS
9.4 Critical
CVSS3