Описание
OOB read / info leak in convert.* stream filters when line-break-chars contains NUL
Summary
The convert.base64-encode, convert.quoted-printable-encode and convert.quoted-printable-decode stream filters accept a line-break-chars option whose length is tracked separately from the string itself. The filter constructors duplicate the value with pestrdup(), which stops at the first NUL byte, while keeping the original length. When the filter later emits a line break it copies the recorded length out of the truncated allocation, reading past its end and placing adjacent heap bytes into the filter output.
Details
php_conv_base64_encode_ctor() duplicates the option with pestrdup() but stores the untruncated length:
https://github.com/php/php-src/blob/php-8.5.10/ext/standard/filters.c#L237-L238
php_conv_qprint_encode_ctor() and php_conv_qprint_decode_ctor() repeat the same pattern at lines 838 and 1051. The over-read happens when the encoder inserts a line break and copies lbchars_len bytes from that allocation:
https://github.com/php/php-src/blob/php-8.5.10/ext/standard/filters.c#L406
With line-break-chars set to "\0X" the duplicate is a one-byte allocation holding only the NUL terminator, while lbchars_len is still 2, so one byte past the allocation is copied into the output. Extending the option after the NUL increases the number of bytes read out of bounds.
The fix replaces pestrdup() with pestrndup(lbchars, lbchars_len, persistent) in all three constructors, so the allocation always matches the recorded length.
PoC
The line break in the output should be the two bytes 0058. Instead the second byte comes from adjacent memory, and AddressSanitizer reports:
The same leak is reachable over HTTP wherever an application forwards request data into the filter options:
Impact
Heap memory adjacent to the line-break-chars allocation is copied into the filter output, so an application that returns the encoded result discloses those bytes to the requester. The attacker can enlarge the leak by lengthening the option value after the NUL byte. A crash is possible on some allocators and builds, but the practical risk is the information leak.
Exploitation requires the application to pass attacker-controlled bytes as line-break-chars and for those bytes to contain an embedded NUL, which is rare in practice, so the majority of applications are not affected.
Пакеты
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
Связанные уязвимости
The convert.base64-encode, convert.quoted-printable-encode and convert.quoted-printable-decode stream filters accept a line-break-chars option whose length is tracked separately from the string itself. The filter constructors duplicate the value with pestrdup(), which stops at the first NUL byte, while keeping the original length. When the filter later emits a line break it copies the recorded length out of the truncated allocation, reading past its end and placing adjacent heap bytes into the filter output.
The convert.base64-encode, convert.quoted-printable-encode and convert.quoted-printable-decode stream filters accept a line-break-chars option whose length is tracked separately from the string itself. The filter constructors duplicate the value with pestrdup(), which stops at the first NUL byte, while keeping the original length. When the filter later emits a line break it copies the recorded length out of the truncated allocation, reading past its end and placing adjacent heap bytes into the filter output.
The convert.base64-encode, convert.quoted-printable-encode and convert.quoted-printable-decode stream filters accept a line-break-chars option whose length is tracked separately from the string itself. The filter constructors duplicate the value with pestrdup(), which stops at the first NUL byte, while keeping the original length. When the filter later emits a line break it copies the recorded length out of the truncated allocation, reading past its end and placing adjacent heap bytes into the filter output.
OOB read / info leak in convert.* stream filters when line-break-chars contains NUL
The convert.base64-encode, convert.quoted-printable-encode and convert ...