Описание
Reference counting in php_request_shutdown causes Use-After-Free
Summary
Exception handler frees variables via cleanup_live_vars
for termination. However, the subsequent php_request_shutdown
performs reference counting on these variables using zend_gc_refcount
(read) and zend_gc_delref
(write), resulting in use-after-free. Since zend_mm_free_small
stores metadata in freed memory chunks, this use-after-free vulnerability may allows manipulation of the Zend allocator through reference count behaviors.
Details
- OS: Ubuntu 22.04 (x86)
- PHP Version: php-8.4.0beta5
- FYI: A similar bug with the handler (#10169) was reported two years ago and patched, but it just increased the reference count before the handler.
- free: the object has a zero reference when the exception occurs, and it frees the object by
_efree
._efree
callszend_mm_free_small
internally, which writes the reference count-overlapping area to managezend_mm_free_slot
(Zend/zend_alloc.c:1434). - access: after the exception is processed, the program requests
php_request_shutdown
, and starts to destroy the variables using destructors. In this step, PHP inspects the reference count to prevent double-free. However, the reference count is no longer valid, and it reads the part of the Zend metadata managed byzend_mm_free_small
. - *undefined behavior: After the first UAF, it subsequently accesses the variables and invoke
zend_gc_delref
as well. Thus, it manipulates the metadata ofzend_mm_free_small
. Moreover, since the metadata contains typically larger value than the original reference count, the GC also lead to undefined behavior.
PoC
In PoC, Foo
class has an echo
for the non-defined constant HI
, and $foo->foo()->baz ??= 1
triggers this exception.
Build command
Run with
Impact
This is a heap use-after-free vulnerability. It occurs because reference counting is performed after live variables are destroyed by exception handlers, resulting in the manipulation of the metadata of Zend allocator. Any component that can create variables, trigger exceptions, and terminate with php_request_shutdown is affected (including PHP CLI and PHP-fuzz-execute).
To exploit this, an attacker would have to:
- Find an application with code similar to this
- Ensure that an exception is thrown in
__set
(it is unlikely that real code will have a statement that always throws here) - Exploit the use-after-free
This is unlikely but possible.
Version
This is present only in PHP 8.3+. The PHP 8.2 and versions before are not impacted.
Пакеты
< 8.3.18
8.3.19
< 8.4.5
8.4.5
Связанные уязвимости
In PHP versions 8.3.* before 8.3.19 and 8.4.* before 8.4.5, a code sequence involving __set handler or ??= operator and exceptions can lead to a use-after-free vulnerability. If the third party can control the memory layout leading to this, for example by supplying specially crafted inputs to the script, it could lead to remote code execution.
In PHP versions 8.3.* before 8.3.19 and 8.4.* before 8.4.5, a code sequence involving __set handler or ??= operator and exceptions can lead to a use-after-free vulnerability. If the third party can control the memory layout leading to this, for example by supplying specially crafted inputs to the script, it could lead to remote code execution.
In PHP versions 8.3.* before 8.3.19 and 8.4.* before 8.4.5, a code sequence involving __set handler or ??= operator and exceptions can lead to a use-after-free vulnerability. If the third party can control the memory layout leading to this, for example by supplying specially crafted inputs to the script, it could lead to remote code execution.
In PHP versions 8.3.* before 8.3.19 and 8.4.* before 8.4.5, a code seq ...
Уязвимость функции php_request_shutdown интерпретатора языка программирования PHP, позволяющая нарушителю выполнить произвольный код