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

exploitDog

github логотип

GHSA-88hq-2827-7pg6

Опубликовано: 24 сент. 2026
Источник: github
Github: Не прошло ревью
CVSS3: 5.9

Описание

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

USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 ./sapi/cli/php -n -r ' $opts = ["line-length" => 4, "line-break-chars" => "\0X"]; $fp = fopen("php://temp", "r+"); fwrite($fp, str_repeat("A", 6)); rewind($fp); stream_filter_append($fp, "convert.base64-encode", STREAM_FILTER_READ, $opts); echo bin2hex(stream_get_contents($fp)), "\n"; '

The line break in the output should be the two bytes 0058. Instead the second byte comes from adjacent memory, and AddressSanitizer reports:

==1271431==ERROR: AddressSanitizer: heap-buffer-overflow READ of size 2 at 0x7bb9d15e2731 thread T0 0x7bb9d15e2731 is located 0 bytes after 1-byte region [0x7bb9d15e2730,0x7bb9d15e2731) #1 php_conv_base64_encode_convert ext/standard/filters.c:406 #2 strfilter_convert_append_bucket ext/standard/filters.c #3 strfilter_convert_filter ext/standard/filters.c:1513

The same leak is reachable over HTTP wherever an application forwards request data into the filter options:

<?php $opts = [ "line-length" => 4, "line-break-chars" => base64_decode($_GET["lb64"]), // e.g. "\0X" ]; $fp = fopen("php://temp", "r+"); fwrite($fp, str_repeat("A", 6)); rewind($fp); stream_filter_append($fp, "convert.base64-encode", STREAM_FILTER_READ, $opts); echo bin2hex(stream_get_contents($fp));

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

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

>=8.2.0, <8.2.34

8.2.34

Наименование

php

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

>=8.3.0, <8.3.35

8.3.35

Наименование

php

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

>=8.4.0, <8.4.26

8.4.26

Наименование

php

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

>=8.5.0, <8.5.11

8.5.11

EPSS

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

5.9 Medium

CVSS3

Дефекты

CWE-122
CWE-125

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

CVSS3: 5.9
ubuntu
8 дней назад

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.

CVSS3: 5.9
redhat
8 дней назад

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.

CVSS3: 5.9
nvd
8 дней назад

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.

CVSS3: 5.9
msrc
4 дня назад

OOB read / info leak in convert.* stream filters when line-break-chars contains NUL

CVSS3: 5.9
debian
8 дней назад

The convert.base64-encode, convert.quoted-printable-encode and convert ...

EPSS

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

5.9 Medium

CVSS3

Дефекты

CWE-122
CWE-125