PHP 7.4–8.1 без пакетов: собираем патч PHP2Shell сами
АйТи Фреш
Информационная безопасность

Как собрать PHP 7.4, 8.0 или 8.1 с патчем PHP2Shell из GitHub, если пакетов нет

Автор: , директор ООО «АйТи-Фреш» · · ~14 мин чтения
Сборка PHP с патчем CVE-2026-109618 на сервере, метафора ремонта безопасности
Своя сборка PHP — запасной путь, когда готовых пакетов с патчем нет.

Для PHP 7.4, 8.0 и 8.1 официальных релизов с патчем PHP2Shell нет, но готовые пакеты всё же бывают: Ubuntu 22.04 выпустила php8.1 8.1.2-1ubuntu2.28, Plesk пересобрал 7.4.33/8.0.30/8.1.34 21 октября, TuxCare ELS даёт alt-php для всех трёх веток. Если ни один из этих путей вам не подходит, остаётся собрать PHP самому из веток php-src, куда команда безопасности PHP выложила минимальные бэкпорты. Покажу, как сделать это в отдельный префикс, поднять рядом второй мастер FPM и переключить сайт с возможностью отката за минуту.

Когда сборка из исходников действительно нужна

PHP 7.4, 8.0 и 8.1 — EOL, новых релизов php.net для них не будет. Вместо этого 21 октября команда безопасности PHP выложила в php/php-src три ветки: PHP-7.4-CVE-2026-109618-109619, PHP-8.0-CVE-2026-109618-109619 и PHP-8.1-CVE-2026-109618-109619 — минимальные исходные патчи для тех, кто собирает сам или живёт без LTS-вендора. Прежде чем открывать терминал, я бы проверил три вещи: нет ли бэкпорта в вашем дистрибутиве (Ubuntu 22.04 — php8.1 8.1.2-1ubuntu2.28 по USN-8948-1), не стоит ли на сервере Plesk (там патч приехал в сборках от 21.10 без смены номера версии) и не дешевле ли подписка TuxCare ELS с пакетами alt-php в /opt/alt/. Сборка — это когда все три ответа «нет»: CentOS 7, самосборный стек, PHP без пакетного менеджера. Не тратьте время на поиск несуществующих пакетов в стандартных репозиториях, их там нет.

Это условный пример. Конструкторское бюро «Хорда», 16 рабочих мест: внутренний калькулятор проектов на PHP 8.1, сервер на CentOS 7, пакетов с патчем нет и не будет, переписывать калькулятор под 8.3 — недели. Паниковать при этом не нужно: по данным Sansec на 22.10, публичные эксплойты не работают на стандартной установке и для большинства из них нужна ещё и уязвимость локального включения файлов в приложении. Но «маловероятно» — не «невозможно», а патч закрывает обе дыры полностью. Поэтому план такой: в первый час — session.upload_progress.enabled = 0 и ограничение доступа к сайту, в тот же день — сборка 8.1 из ветки с бэкпортом в отдельный префикс, а в планах на квартал — миграция на поддерживаемую ветку. Главное заблуждение — что номер версии говорит о патче. Бэкпорты дистрибутивов, Plesk и ELS обычно сохраняют старый номер: Ubuntu 24.04 после патча так и показывает 8.3.6, Plesk — те же 8.1.34. Для пакета правду говорит changelog (apt-get changelog php8.1-fpm | grep -i cve-2026-1096) и дата сборки. Для собственной сборки дата ничего не доказывает — доказывает хэш коммита ветки с бэкпортом, из которой вы собирали. И ещё: Remi для 7.4 заморожен на 7.4.33, ждать там патча бессмысленно — это как раз тот случай, когда сборка оправдана.

Если вы видите ошибку в логах при попытке обновиться через apt или yum, не пытайтесь «починить» репозиторий. Это тупик. Единственный выход — либо платная подписка ELS, либо ручная сборка. Мы в ITfresh часто сталкиваемся с ситуацией, когда клиент уверен, что у него «последняя версия 8.1», потому что php -v выдает 8.1.34, но дата сборки — март 2026 года. Это ловушка. Патч вышел 21 октября. Если дата сборки раньше — вы уязвимы. Сборка из исходников позволяет контролировать каждый байт кода, который попадает на ваш сервер, но требует дисциплины. Никаких «быстрых решений» здесь быть не может. Только точное следование инструкции и проверка каждого шага.

Внимание: Сборка из исходников не дает автоматических обновлений безопасности в будущем. Вам придется отслеживать новые CVE и пересобирать PHP вручную при каждом выходе патча.
Схема этапов сборки PHP с патчем из исходников
Последовательность действий от клонирования до переключения FPM.

Подготовка окружения и клонирование правильной ветки

Для сборки нужны компилятор и заголовки библиотек: на Debian/Ubuntu — build-essential autoconf bison re2c pkg-config libxml2-dev libssl-dev libcurl4-openssl-dev libzip-dev libonig-dev libsqlite3-dev плюс -dev-пакеты под ваши расширения (libpng, libjpeg, libfreetype для GD, libicu для intl); на RHEL-подобных — gcc make autoconf bison re2c и соответствующие *-devel. bison и re2c обязательны именно для сборки из git, в release-архивах они не нужны. Ставим всё в отдельный префикс, например /opt/php-8.1-patched, чтобы ни один файл не лёг в /usr. Откат тогда — это просто вернуть веб-сервер на старый сокет. Не экономьте место на диске: сборка может занять 1–2 ГБ временного пространства. Если диск переполнится посреди make, процесс упадет, и вы потеряете время. Проверьте свободное место командой df -h перед началом.

Следующий шаг — получение исходного кода. Не скачивайте архив с главной страницы, там будет старая версия. Нам нужны специальные ветки с бэкпортом. Переходим в директорию сборки и клонируем репозиторий, выбирая нужную ветку. Для PHP 8.1 это ветка PHP-8.1-CVE-2026-109618-109619. Для 8.0 — PHP-8.0-CVE-2026-109618-109619, для 7.4 — PHP-7.4-CVE-2026-109618-109619. Важно: эти ветки содержат минимальный набор исправлений именно для уязвимостей PHP2Shell. Они не включают в себя другие фичи или багфиксы, кроме тех, что необходимы для закрытия дыр. Это гарантирует максимальную стабильность для вашего старого приложения. Ошибиться в названии ветки легко, и тогда вы получите код без патча, что бессмысленно. Используйте git clone --depth 50 --branch PHP-8.1-CVE-2026-109618-109619 https://github.com/php/php-src.git php-8.1-build. Флаг --depth 50 ускорит скачивание, но не даст полную историю, что нормально для нашей задачи.

Клонируем только нужную ветку: git clone --depth 50 --branch PHP-8.1-CVE-2026-109618-109619 https://github.com/php/php-src.git php-8.1-build. Внутри смотрим git log --oneline -5: последние коммиты должны ссылаться на CVE-2026-109618 и CVE-2026-109619 (или на GHSA-w8hw-w9fx-j79w и GHSA-6wmf-4rv5-p3rp). Хэш верхнего коммита я записываю в build.sh и в README рядом с префиксом — через полгода это единственное доказательство, из какого кода собран бинарник. Если вы увидите в логе старые коммиты без упоминания CVE, значит, вы клонировали не ту ветку или ветка была обновлена неправильно. В таком случае удаляйте директорию и начинайте заново. Не пытайтесь «подправить» ветку вручную — это приведет к нестабильности.

Настройка конфигурации и сборка с нужными расширениями

В git-клоне нет готового configure, поэтому сначала ./buildconf --force — это обязательный шаг, а не «если нужно». Затем снимаем список модулей с текущего PHP (php -m > modules.txt) и превращаем его в ключи configure. Минимальный набор для сайта на FPM: ./configure --prefix=/opt/php-8.1-patched --with-config-file-path=/opt/php-8.1-patched/etc --with-config-file-scan-dir=/opt/php-8.1-patched/etc/conf.d --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data --disable-cgi --with-openssl --with-curl --with-zlib --enable-mbstring --enable-intl --with-zip --enable-gd --with-jpeg --with-freetype --with-pdo-mysql=mysqlnd --with-mysqli=mysqlnd --enable-opcache. Без --enable-fpm FPM просто не соберётся. Если сайт работает через Apache mod_php — вместо FPM нужен --with-apxs2. Команду сохраняем в build.sh. Не копируйте слепо команды из интернета: ваш сервер может требовать других флагов. Например, mysqlnd — встроенный драйвер, клиентские библиотеки MySQL ему не нужны, а вот для intl понадобится libicu-dev.

Расширения не из php-src (redis, imagick, apcu, xdebug) в configure не включаются: их собирают после установки через /opt/php-8.1-patched/bin/pecl install или phpize из исходников расширения и подключают ini-файлом в conf.d. Важно брать версию расширения, которая ещё поддерживает 8.1 или 7.4. Если configure остановился с ошибкой — почти всегда не хватает -dev-пакета: в сообщении будет имя библиотеки, ставим её заголовки и запускаем build.sh заново. Типичная ошибка — забыть про libxml2-dev или libonig-dev, что приводит к падению сборки mbstring или json. Читайте вывод configure внимательно: он прямо говорит, чего не хватает. Не игнорируйте предупреждения — они могут стать фатальными ошибками позже.

Дальше make -j$(nproc): на 4–8 ядрах это 5–20 минут. Перед установкой — проверка: ./sapi/cli/php -v и ./sapi/cli/php -m против modules.txt, затем make test (полный прогон долгий, хотя бы TESTS=Zend/tests и ext/session/tests). Отдельные упавшие тесты на старой ветке и новой ОС — не повод паниковать, массовые падения — повод остановиться. Учтите: -v покажет номер ветки, а не факт патча; патч подтверждает только коммит, из которого вы собирали. После этого make install. Если make test падает с ошибками в Zend/tests, проверьте, не конфликтует ли новая сборка с системными библиотеками. Иногда помогает пересборка с флагом --disable-all и постепенным добавлением модулей, чтобы найти виновника.

Не игнорируйте ошибки configure! Если библиотека не найдена, модуль не соберется, и приложение не запустится. Установите недостающие dev-пакеты перед повторным запуском.
Сравнение рисков установки PHP поверх системы и в отдельный префикс
Изоляция новой сборки — залог безопасного обновления.

Установка в префикс и переключение PHP-FPM

Ключевая ошибка — положить новый пул в /etc/php/8.1/fpm/pool.d/: его подхватит старый, уязвимый мастер. Новому PHP нужен свой мастер. Копируем sapi/fpm/php-fpm.conf и www.conf в /opt/php-8.1-patched/etc/, задаём свой pid (/run/php81p.pid) и свой сокет (listen = /run/php/php81-patched.sock). Затем отдельный юнит /etc/systemd/system/php81-patched-fpm.service с ExecStart=/opt/php-8.1-patched/sbin/php-fpm --nodaemonize --fpm-config /opt/php-8.1-patched/etc/php-fpm.conf и ExecReload=/bin/kill -USR2 $MAINPID. Сразу кладём в conf.d временные меры: session.upload_progress.enabled = 0 лишней не будет. Не используйте стандартные пути для PID и сокетов — это приведёт к конфликтам с системным PHP. Убедитесь, что пользователь www-data имеет права на запись в директорию сокета.

Проверка и запуск: /opt/php-8.1-patched/sbin/php-fpm -t -y /opt/php-8.1-patched/etc/php-fpm.conf, затем systemctl daemon-reload && systemctl enable --now php81-patched-fpm. В nginx меняем fastcgi_pass на unix:/run/php/php81-patched.sock и делаем nginx -t && systemctl reload nginx — reload без обрыва соединений. Старый мастер оставляем запущенным на час-два как путь отката, но без публичного трафика; после проверки останавливаем его и отключаем: пока он работает, на сервере живёт уязвимый PHP. Если nginx -t выдаст ошибку, проверьте права на сокет: он должен быть доступен пользователю nginx. Часто проблема в том, что сокет создан с правами 0660, а nginx работает от имени www-data, которому нужен доступ.

Проверяем, кто реально отвечает сайту: ps -eo pid,lstart,args | grep '[p]hp-fpm: master' должен показать мастер из /opt/php-8.1-patched с только что начавшимся временем запуска. Через веб — временный файл с <?php echo PHP_BINARY, ' ', PHP_VERSION, ' ', ini_get('session.upload_progress.enabled'); и сразу удалить. phpinfo() на боевом сервере я не оставляю даже на минуту. Затем прогоняем ключевые сценарии сайта: вход, формы, загрузку файлов. Если видите 502 Bad Gateway, проверьте, не упал ли новый мастер FPM. Посмотрите логи нового мастера: error_log из /opt/php-8.1-patched/etc/php-fpm.conf. Сообщения «exited on signal 11» говорят о несовместимости расширений. В таком случае верните трафик на старый сокет и пересоберите проблемное расширение под новый PHP.

Не хотите собирать сами — мы проверим, есть ли для вашего сервера готовый бэкпорт, и если нет, соберём PHP из ветки с патчем в отдельный префикс, поднимем второй мастер FPM и переключим сайт с проверкой и планом отката. Обсудить задачу

План отката и поддержка обновлений

Сборка из исходников — это не «поставил и забыл». Вам нужно иметь четкий план отката. Если новая версия PHP вызовет проблемы с приложением (что бывает, особенно при старом коде), вы должны вернуть всё назад за 5 минут. Для этого сохраните резервные копии всех конфигов Nginx/Apache и FPM до начала работ. Также убедитесь, что старый PHP-пул продолжает работать и доступен. В «Хорде» мы сделали это простым переключением в конфиге Nginx: закомментировали новую строку и раскомментировали старую, затем nginx -s reload. Это мгновенно вернуло трафик на старую версию без простоя. Отсутствие плана отката — это профессиональная халатность, которая может стоить бизнеса. Не удаляйте старый PHP сразу: дайте ему поработать параллельно минимум сутки, пока вы мониторите логи и поведение сайта.

Также важно помнить про обновления. Бэкпорт CVE-2026-109618/109619 — это первый шаг. В будущем могут выйти новые патчи для этих старых веток. Вам придется следить за официальным репозиторием PHP на GitHub. Когда выйдет новый патч, вам нужно будет снова клонировать ветку, применить изменения, пересобрать и переустановить. Автоматизировать это сложно, но возможно через скрипты CI/CD. Я рекомендую настроить мониторинг версий PHP и оповещения о новых CVE. Если вы не готовы поддерживать сборку вручную, рассмотрите возможность миграции на поддерживаемую версию PHP или использования платных ELS-решений, таких как TuxCare. Постоянная поддержка устаревшего ПО требует ресурсов. Не забывайте, что сборка из исходников не гарантирует защиту от будущих уязвимостей, если вы не будете регулярно обновлять код.

Первые сутки смотрим логи: /var/log/nginx/error.log и лог нового мастера (error_log из /opt/php-8.1-patched/etc/php-fpm.conf). Сообщения «exited on signal 11» и серии 502 — сигнал несовместимости расширения или библиотеки; обычно лечится пересборкой расширения под новый PHP. Обратный путь — вернуть fastcgi_pass на старый сокет и reload nginx, но помните: это возврат на уязвимый PHP, значит — сразу с временными мерами и ограничением доступа. Если вы видите в логах ошибки типа «segmentation fault», это признак того, что расширение не совместимо с новой версией PHP. В таком случае откатитесь на старый сокет и пересоберите расширение, используя pecl install или phpize из исходников. Не пытайтесь «починить» расширение на лету — это опасно.

Чеклист проверки безопасности после сборки PHP с патчем
Шесть шагов, чтобы убедиться в защите сервера.

Частые вопросы

Можно ли просто обновить PHP через apt/yum для версии 7.4?

Из стандартных репозиториев — нет, PHP 7.4 там не поддерживается. Готовые пакеты есть у TuxCare ELS (alt-php74, apt-get/yum update alt-php*) и у Plesk (7.4.33 в сборках от 21.10.2026). Remi php74 заморожен на 7.4.33 без патча. Если ничего из этого нет — сборка из ветки PHP-7.4-CVE-2026-109618-109619.

Нужно ли удалять старый PHP после установки нового?

Нет, лучше оставить его для отката. Работайте с двумя версиями параллельно, используя разные пулы FPM.

Как проверить, что патч действительно применен?

Для своей сборки — хэш коммита ветки PHP-x.y-CVE-2026-109618-109619, записанный при сборке, плюс проверка, что сайт обслуживает новый мастер (ps lstart, PHP_BINARY). Для пакетов — changelog со ссылкой на CVE-2026-109618, а у Plesk — дата сборки не раньше 21.10.2026.

Можно ли использовать этот метод для PHP 7.3?

Веток с бэкпортом для 7.3 у php.net нет — официально «upgrade to a supported branch». Но в ppa ondrej/php для Ubuntu 21.10 вышел php7.3 7.3.33-35 с исправлением обеих CVE. Это временный вариант: 7.3 давно EOL, планируйте переход на 8.2+.

Сколько времени занимает сборка PHP из исходников?

Компиляция — 5–20 минут. С подготовкой зависимостей, make test, юнитом FPM и проверкой сайта закладывайте 2–4 часа на один сервер.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи