В PHP-FPM, менеджере процессов FastCGI, входящем в основную поставку PHP начиная с ветки 5.3, выявлена критическая уязвимость CVE-2021-21703, дающая возможность непривилегированному пользователю хостинга выполнить код с правами root. Проблема проявляется на серверах, использующих для организации запуска PHP-скриптов PHP-FPM, обычно применяемый в связке с Nginx. Выявившие проблему исследователи смогли подготовить рабочий прототип эксплоита.
Уязвимость вызвана сохранением указателей в область разделяемой памяти (scoreboard), применяемой для организации взаимодействия между дочерним и родительским процессом PHP-FPM. Основной процесс PHP-FPM, координирующий работу, запускается с правами root и порождает несколько дочерних процессов, которые выполняются под непривилегированным пользователем (обычно www-data или nobody) и непосредственно занимаются выполнением PHP-скриптов. Суть проблемы в том, что подконтрольный пользователю дочерний процесс может получить доступ к разделяемой памяти управляющего процесса и изменить указатели, используемые в основном процессе (в структуре scoreboard сохраняются указатели на вложенную структуру fpm_scoreboard_proc_s).
Указанная особенность позволяет атакующему, который имеет возможность запустить свой PHP-код на сервере, обойти sandbox-изоляцию интерпретатора и через подмену указателей в структуре fpm_scoreboard_s очистить область памяти основного процесса или изменить значение 32-разрядных целых значений с нуля на единицу. Для изменения значения атакующий записывает указатель на целочисленную переменную в массив scoreboard->procs и отправляет связанному с этим указателем обработчику сигнал SIGKILL.
Подобные манипуляции дают возможность через проявление ещё одной ошибки добиться выполнения своего кода в основном процессе. В частности, в памяти можно установить в 1 настройку catch_workers_output, которая по умолчанию имеет значение 0. Указанная настройка включает сохранение в лог stderr-вывода от рабочих процессов php-fpm. Поступающая информация буферизируется, а буфер создаётся в куче основного процесса, что позволяет атакующему разместить в куче до 1024 байт произвольных данных. Далее манипулируя возможностью менять 0 на 1 и очищать память, атакующий может изменить размера блока и добиться контролируемого переполнения кучи.
Уязвимость проявляется начиная с версии PHP 5.3.7, в которую был интегрирован PHP-FPM. Примечательно, что разработчики PHP были уведомлены о проблеме ещё в мае, но не спешили с подготовкой исправления. В итоге уязвимость была устранена в обновлениях PHP 7.3.32, 8.0.12 и 7.4.25 уже после раскрытия сведений о проблеме. Для веток PHP, поддержка которых уже прекращена, можно попытаться использовать патч. Основные дистрибутивы выпустили обновления пакетов с устранением уязвимости: Debian, RHEL, SUSE, Ubuntu, Fedora, Arch. В портах FreeBSD проблема пока не устранена.
В 2019 году похожая уязвимость, также связанная с хранением указателей в разделяемой памяти scoreboard, была исправлена в механизме управления дочерними процессами в Apache httpd. Уязвимость позволяла локальному злоумышленнику (например, пользователю хостинга), имеющему возможность выполнить свой скрипт под управлением web-сервера, добиться выполнения кода с правами управляющего процесса, обычно запускаемого с привилегиями root.