Описание
Heap-buffer-overflow in php_openssl_matches_wildcard_name on crafted server cert wildcard CN
Summary
php_openssl_matches_wildcard_name() in ext/openssl/xp_ssl.c underflows the length argument passed to memchr() when a TLS server certificate presents a wildcard name whose literal characters are together longer than the hostname being verified. A malicious server presenting such a certificate makes the PHP client read up to SIZE_MAX bytes past the end of a heap allocation. The path is reachable from any default client stream, because verify_peer_name is enabled by default.
Details
The guard before the memchr() call only accounts for the suffix length:
https://github.com/php/php-src/blob/php-8.5.10/ext/openssl/xp_ssl.c#L435-L441
The third argument is subject_len - suffix_len - prefix_len. subject_len and suffix_len are size_t while prefix_len is ptrdiff_t, so the usual arithmetic conversions promote the whole expression to size_t. With a certificate name of aaa*aa verified against aaaa, the prefix is 3 and the suffix is 2 against a 4-byte subject, so the length computes as (size_t)(4 - 2 - 3) and wraps to SIZE_MAX. memchr() then scans from subjectname + prefix_len until it finds a . or hits unmapped memory.
The fix makes prefix_len a size_t and changes the guard to suffix_len + prefix_len <= subject_len, so the subtraction can no longer wrap.
PoC
Create a CA and a server certificate whose CN is a wildcard pattern longer than the hostname:
Serve it from a local TLS listener, then run the client with a shorter peer_name:
USE_ZEND_ALLOC=0 is needed so that AddressSanitizer sees the boundary of the heap-allocated peer name; with the Zend allocator the read still happens but stays inside a pre-allocated chunk. In a production build without a sanitizer the scan continues through the libc heap until it finds a . or reaches an unmapped page and the process crashes.
Impact
A server that a PHP client connects to over TLS can cause an out-of-bounds read of unbounded length during hostname verification, crashing the process and producing a denial of service. The scan stops at the first . byte it encounters and its result only feeds the accept or reject decision, so no heap content is returned to the attacker.
It applies to any client stream using the default verify_peer_name, including file_get_contents(), fopen() and stream_socket_client() on https:// and tls://. The attacker must be able to present the crafted certificate, either by controlling the server or by being trusted through the CA in use.
Пакеты
php
>=8.2.0, <8.2.34
8.2.34
php
>=8.3.0, <8.3.35
8.3.35
php
>=8.4.0, <8.4.26
8.4.26
php
>=8.5.0, <8.5.11
8.5.11
Связанные уязвимости
php_openssl_matches_wildcard_name() in ext/openssl/xp_ssl.c underflows the length argument passed to memchr() when a TLS server certificate presents a wildcard name whose literal characters are together longer than the hostname being verified. A malicious server presenting such a certificate makes the PHP client read up to SIZE_MAX bytes past the end of a heap allocation. The path is reachable from any default client stream, because verify_peer_name is enabled by default.
php_openssl_matches_wildcard_name() in ext/openssl/xp_ssl.c underflows the length argument passed to memchr() when a TLS server certificate presents a wildcard name whose literal characters are together longer than the hostname being verified. A malicious server presenting such a certificate makes the PHP client read up to SIZE_MAX bytes past the end of a heap allocation. The path is reachable from any default client stream, because verify_peer_name is enabled by default.
php_openssl_matches_wildcard_name() in ext/openssl/xp_ssl.c underflows the length argument passed to memchr() when a TLS server certificate presents a wildcard name whose literal characters are together longer than the hostname being verified. A malicious server presenting such a certificate makes the PHP client read up to SIZE_MAX bytes past the end of a heap allocation. The path is reachable from any default client stream, because verify_peer_name is enabled by default.
Heap-buffer-overflow in php_openssl_matches_wildcard_name on crafted server cert wildcard CN
php_openssl_matches_wildcard_name() in ext/openssl/xp_ssl.c underflows ...