Новости Нулевой байт сломал защиту PHP и открыл путь к SQL-инъекции

NewsMaker

I'm just a script
Премиум
28,202
46
8 Ноя 2022
Positive Technologies обнаружила две критические уязвимости в драйверах PDO для PHP.

<div class="articl-text-cover" style="position:relative;width:100%;max-width:800px;margin-left:auto;margin-right:auto;aspect-ratio:800/450;margin-bottom:2rem;overflow:hidden">
4ptr7tfyh5pjlw9lxj78ke9293xr99hq.png

Исследователи Positive Technologies нашли в PHP две ошибки на стыке привычного кода веб-приложений и низкоуровневых драйверов баз данных. Одна уязвимость открывала путь к SQL-инъекции в драйвере Firebird через нулевой байт в строке, а другая могла ронять PHP-процесс при работе с PostgreSQL. Обе проблемы затрагивали PDO, стандартный слой PHP для работы с разными базами данных через единый интерфейс.

PDO используют тысячи приложений: разработчик пишет запросы через знакомый объектный API, а конкретный драйвер передает команды MySQL, PostgreSQL, Firebird, SQLite или другой СУБД. Удобная абстракция скрывает много низкоуровневых деталей. Исследование показало, что ошибки в обработке строк внутри драйверов могут сломать даже защитные механизмы, которым разработчики привыкли доверять годами.

Первая уязвимость получила идентификатор CVE-2025-14179 и высокий уровень опасности. Проблема находилась в pdo_firebird, драйвере PDO для Firebird. Исследователи Алексей Соловьев и Никита Свешников выяснили, что функция экранирования PDO::quote корректно обрабатывала специальные символы и нулевые байты, но последующая подготовка SQL-запроса в PDO::prepare ломала структуру строки.

Ошибка возникала во время повторного разбора и сборки SQL-запроса внутри драйвера Firebird. Драйвер использовал функцию strncat(), которая в языке C воспринимает нулевой байт как конец строки. Если пользовательский ввод содержал \0, драйвер обрезал строковый литерал и терял закрывающую кавычку. После потери границы строки фрагменты запроса, которые должны были оставаться обычными данными, могли попасть в исполняемый SQL-контекст.

На практике атака требовала определенного шаблона кода: приложение сначала экранировало пользовательский ввод через PDO::quote, затем вставляло результат в динамический SQL-запрос и передавало готовую строку в PDO::prepare. Многие разработчики считают такой подход безопасным, потому что ввод проходит через штатный механизм экранирования. В случае pdo_firebird защита ломалась позже, уже во время внутренней подготовки запроса драйвером.

В демонстрации исследователи показали, как нулевой байт в имени пользователя и специально подобранное значение второго параметра позволяли выполнить UNION SELECT и получить служебные данные Firebird, включая версию движка базы данных. Вместо пустого результата приложение возвращало записи из таблицы пользователей и системную информацию. Поддерживающие PHP разработчики закрыли CVE-2025-14179 в мае 2026 года, заменив небезопасную сборку строк на бинарно-безопасную обработку фрагментов с учетом фактической длины данных.

Вторая уязвимость получила идентификатор CVE-2025-14180 и оценку 6,3 балла из десяти. Проблема затрагивала pdo_pgsql при работе с PostgreSQL, если приложение явно включало эмуляцию подготовленных выражений через PDO::ATTR_EMULATE_PREPARES. В таком режиме PDO производил эмуляцию на уровне языка, а не СУБД: подставлял параметры в шаблон SQL-запроса, экранировал значения на стороне PHP и отправлял серверу готовый SQL-запрос.

Сбой возникал в абстрактном расширении PDO при передаче параметра с недопустимой многобайтовой последовательностью для текущей кодировки соединения. Клиентская библиотека PostgreSQL libpq сообщала об ошибке экранирования, драйвер pdo_pgsql возвращал NULL, а парсер PDO продолжал обращаться к результату как к обычной строке. Макрос Zend Engine пытался прочитать длину строки по нулевому указателю, после чего операционная система завершала PHP-процесс с ошибкой сегментации.

Для веб-приложения подобный сбой означает отказ в обслуживании: PHP-воркер аварийно завершается, а блок try/catch не будет вызван и не сможет обработать исключение. Исследователи отдельно показали бизнес-риск на примере условного сервиса продажи цифровых лицензий. Приложение успевало списать деньги с баланса пользователя, затем падало при сохранении комментария к заказу с некорректным байтом. Запись о заказе не создавалась, складской остаток не менялся, счет не формировался, а пользователь видел ошибку бэкенда.

Опасность усиливается в многошаговых операциях без явных транзакций. Если приложение полагается на автокоммит, часть изменений может попасть в базу до падения процесса, а последующие действия не выполнятся. В распределенной архитектуре похожий сбой способен оставить разные сервисы в несогласованном состоянии, особенно если перед аварийным завершением компонент уже отправил внешний запрос или зафиксировал промежуточную операцию.

Разработчики PHP исправили CVE-2025-14180 16 декабря 2025 года. Исправление добавило проверку результата экранирования перед обращением к длине строки. При ошибке драйвера PDO теперь возвращает обычную ошибку уровня приложения вместо аварийного завершения процесса. Для защиты исследователи рекомендуют обновить PHP минимум до версий 8.1.34, 8.2.30, 8.3.29, 8.4.16 или 8.5.1. Для защиты от SQL-инъекции в pdo_firebird нужно обновить PHP до версий 8.2.31, 8.3.31, 8.4.21, 8.5.6 или новее для Null Pointer Dereference.

Обе уязвимости показывают, что безопасность PHP-приложений зависит не только от кода разработчика, но и от рантайма, расширений и драйверов языка.. Даже привычные механизмы экранирования и подготовленные выражения могут дать сбой на редких входных данных, если низкоуровневая часть стека неверно обрабатывает байты, строки или ошибки. Практическая защита сводится к своевременному обновлению PHP, отказу от лишней эмуляции подготовленных выражений, внимательной обработке бинарного ввода и обязательным транзакциям для финансовых, складских и других многошаговых операций.
 
Источник новости
www.securitylab.ru

Похожие темы