Уязвимость PHP RCE: как работает и как защититься
Три одинаковые плоские плиты, уложенные ровной стопкой, у средней плиты изумрудная боковая грань

Уязвимость PHP RCE: как работает и как защититься

RCE в PHP — это удалённое выполнение кода на сервере. Разбираем причины, известные CVE и способы закрыть уязвимость: обновления, настройки, код.

Уязвимость PHP RCE: что это и почему она опасна

RCE (Remote Code Execution) в PHP — это уязвимость, которая позволяет злоумышленнику выполнить произвольный код на вашем сервере через обычный запрос к сайту. Закрывается она сочетанием мер: своевременным обновлением PHP, CMS и библиотек, строгой фильтрацией пользовательского ввода и жёсткой настройкой сервера.

Уязвимость CVE-2024-4577 в PHP-CGI на Windows получила 9.8 из 10 баллов по шкале CVSS — почти максимальную оценку критичности.

Из всех классов веб-уязвимостей RCE считается самым серьёзным. Если XSS крадёт сессию пользователя, а SQL-инъекция читает данные из базы, то RCE отдаёт атакующему управление самим сервером. Ниже разберём, как возникают такие уязвимости в PHP, какие известные CVE стоит знать и что сделать, чтобы ваш проект не попал в статистику взломов.

Что такое RCE простыми словами

Представьте, что у вашего сайта есть форма, где пользователь вводит адрес для проверки доступности. Скрипт на PHP берёт введённую строку и передаёт её в командную оболочку сервера. Если разработчик не проверил ввод, то вместо адреса можно подставить собственную команду, и сервер её выполнит. Это и есть удалённое выполнение кода: данные превратились в инструкции.

Код при этом исполняется с правами пользователя, от имени которого работает веб-сервер или PHP-FPM (часто это www-data или apache). Кажется, что права ограничены, но их хватает, чтобы прочитать конфигурационные файлы с паролями от базы данных, изменить файлы сайта, загрузить веб-шелл и использовать сервер как плацдарм для дальнейших атак.

RCE бывает двух видов. В первом случае ошибка находится в самом интерпретаторе или в связке PHP с веб-сервером. Во втором ошибка допущена в прикладном коде: в плагине, теме, самописном скрипте или сторонней библиотеке. Второй вид встречается намного чаще.

К чему приводит успешная RCE-атака

  1. 01

    Кража данных: доступ к базе клиентов, заказам, логинам и хешам паролей, файлам .env и конфигурации

  2. 02

    Установка веб-шелла: постоянного «чёрного хода», который остаётся даже после смены паролей

  3. 03

    Внедрение вредоносного кода: скрытые редиректы, подмена контента, рассылка спама с вашего домена

  4. 04

    Использование ресурсов сервера: скрытый майнинг, участие в DDoS-атаках, хостинг фишинговых страниц

  5. 05

    Шифрование данных ради выкупа и полная остановка бизнеса

  6. 06

    Потеря позиций и репутации: поисковые системы, включая Яндекс и Google, помечают заражённые сайты как опасные и могут понизить их в выдаче

Почему именно PHP так часто попадает под удар

PHP работает на огромной доле сайтов в интернете, в том числе на WordPress, Joomla, Drupal, Bitrix, Laravel и Symfony. Большая популярность делает язык привлекательной мишенью: достаточно найти одну ошибку, чтобы получить тысячи потенциальных жертв. Автоматические сканеры проверяют новые уязвимости практически сразу после публикации CVE.

Есть и причины в самом языке. Исторически PHP предоставлял много удобных, но потенциально опасных возможностей: динамическое подключение файлов, выполнение строки как кода, десериализация объектов, прямой вызов команд оболочки. Всё это легко использовать неправильно. Добавьте к этому множество устаревших версий на хостингах и неподдерживаемые плагины, и получите благодатную почву для атак.

Основные причины RCE в PHP

1. Инъекция команд ОС. Пользовательские данные попадают в функции system, exec, shell_exec, passthru, popen, proc_open или в оператор обратных кавычек. Без экранирования и белого списка допустимых значений ввод становится частью команды.

2. Выполнение кода из строки. Функция eval и ряд устаревших приёмов (например, модификатор /e в preg_replace, удалённый в PHP 7) превращают строку в код. Если часть строки приходит от пользователя, это прямая дорога к RCE.

3. Небезопасное подключение файлов (LFI/RFI). Конструкция include с параметром из запроса позволяет подключить чужой файл. Локальное включение часто комбинируют с записью в логи или загрузкой файла, чтобы добиться выполнения кода. Удалённое включение возможно при включённых allow_url_fopen и allow_url_include.

4. Небезопасная десериализация. Функция unserialize с недоверенными данными позволяет создавать объекты и запускать «магические» методы (__wakeup, __destruct). Через цепочки классов в популярных библиотеках получают выполнение кода. Отдельный вектор — архивы phar, которые десериализуются при обращении к файлам через обёртку phar://.

5. Небезопасная загрузка файлов. Если сайт принимает файл и сохраняет его в публичный каталог с исходным расширением, злоумышленник загружает PHP-скрипт и обращается к нему по URL. Проверка только заголовка Content-Type или расширения на стороне клиента не защищает.

6. Ошибки в интерпретаторе и связке с веб-сервером. Примеры: CVE-2012-1823, CVE-2019-11043 и CVE-2024-4577. Их устраняет только обновление PHP и корректная конфигурация.

7. Уязвимые зависимости, плагины и забытые файлы. Устаревшие компоненты, тестовые скрипты и инструменты разработки, оставленные на боевом сервере, нередко содержат готовые точки входа.

схема / цепочка RCE-атаки
Как одна ошибка превращается в полный захват сервера
01 / вход

Ввод попадает в опасную функцию

Параметр запроса, cookie или загруженный файл без проверки передаются в eval, system, include или unserialize.

02 / выполнение

Код запускается на сервере

Команда исполняется с правами пользователя веб-сервера, например www-data.

03 / закрепление

Атакующий остаётся в системе

Появляются веб-шелл, задачи cron, новые ключи SSH и скрытые администраторы CMS.

04 / последствия

Ущерб бизнесу

Утечка базы, редиректы на чужие ресурсы, майнер, рассылка спама, шифрование данных.

Известные случаи: чему они учат

История PHP знает немало громких RCE-уязвимостей. Их полезно изучить не ради любопытства: они показывают, что именно ломается чаще всего и как быстро после публикации CVE начинаются массовые сканирования.

В таблице ниже собраны несколько показательных примеров из разных категорий: ошибки интерпретатора, забытые инструменты разработки, уязвимости в CMS и фреймворках. Проверьте свои версии по этому списку, а затем сверяйтесь с официальными бюллетенями безопасности PHP и вашего фреймворка.

CVEЧто затронутоСуть проблемыКак защититься
CVE-2012-1823PHP-CGI до версий 5.3.12 и 5.4.2Строка запроса без знака равенства передавалась интерпретатору как аргументы командной строкиОбновить PHP, использовать FPM вместо CGI
CVE-2017-9841PHPUnit до 4.8.28 и 5.6.3 (файл eval-stdin.php)Доступный по HTTP скрипт выполнял PHP-код из тела запросаНе ставить dev-зависимости на боевой сервер, закрыть каталог vendor от веба
CVE-2018-7600Drupal 7 и 8 (Drupalgeddon 2)Недостаточная проверка данных форм позволяла выполнить код без авторизацииОбновить ядро Drupal до исправленной версии
CVE-2019-11043PHP-FPM с nginx и fastcgi_split_path_info; PHP до 7.1.33, 7.2.24 и 7.3.11Обработка путей с переводом строки приводила к повреждению памяти и выполнению кодаОбновить PHP и проверить конфигурацию nginx
CVE-2021-3129Laravel с Ignition до 2.5.2 при включённом режиме отладкиСтраница отладки позволяла записать файл и запустить код через десериализацию pharОбновить Ignition, отключить APP_DEBUG на продакшене
CVE-2024-4577PHP-CGI на Windows; версии до 8.1.29, 8.2.20 и 8.3.8Преобразование символов в кодировках Windows позволяло обойти защиту от CVE-2012-1823Обновить PHP, отказаться от CGI на Windows в пользу FastCGI

Какие выводы можно сделать

Во-первых, уязвимости живут годами. CVE-2024-4577 по сути стала обходом защиты, созданной ещё в 2012 году. Во-вторых, самые простые ошибки, вроде забытого тестового файла или включённой отладки, дают тот же результат, что и сложные цепочки эксплуатации. В-третьих, время между публикацией уязвимости и началом массовых атак измеряется днями, поэтому откладывать обновления рискованно.

Теперь перейдём от общей картины к конкретному коду. Посмотрим, какие шаблоны в PHP чаще всего приводят к RCE и чем их заменить.

Типичные ошибки в коде, ведущие к RCE

Главная причина RCE в прикладном коде — передача данных от пользователя в функции, которые исполняют команды или код, без проверки и экранирования.

Опасный подход

  • system('ping ' . $_GET['host']) — строка пользователя попадает прямо в командную оболочку
  • eval($_POST['formula']) — введённый текст исполняется как PHP-код
  • include $_GET['page'] . '.php' — посетитель сам выбирает, какой файл подключить
  • unserialize($_COOKIE['data']) — объекты создаются из недоверенного источника
  • move_uploaded_file с исходным именем и расширением в публичный каталог — можно загрузить PHP-скрипт

Безопасная альтернатива

  1. 01

    Не вызывать оболочку без необходимости: использовать встроенные функции или библиотеки; если вызов неизбежен, применять белый список значений и escapeshellarg

  2. 02

    Вместо eval использовать разбор выражений специализированной библиотекой или фиксированный набор допустимых операций

  3. 03

    Подключать файлы только из белого списка: сопоставлять ключ страницы с заранее известным путём

  4. 04

    Использовать JSON вместо serialize; если unserialize необходим, передавать параметр allowed_classes со значением false или списком разрешённых классов, а данные подписывать

  5. 05

    Генерировать имя файла самостоятельно, проверять тип по содержимому, хранить загрузки вне корня сайта или запрещать там исполнение PHP

Настройка окружения: второй рубеж обороны

Даже если в коде найдётся ошибка, правильная конфигурация сервера может не дать ей превратиться в полноценный захват системы. Это принцип эшелонированной защиты: каждый уровень снижает ущерб от провала предыдущего.

В PHP для этого есть несколько директив: disable_functions отключает опасные функции, open_basedir ограничивает каталоги, к которым имеет доступ скрипт, allow_url_include и allow_url_fopen управляют работой с удалёнными адресами, display_errors и expose_php скрывают лишнюю информацию. На уровне веб-сервера важно запретить исполнение PHP в каталогах загрузок и закрыть доступ к служебным каталогам и файлам вроде vendor, .git и .env.

было / стало
Минимальная гигиена конфигурации PHP-проекта
было
  • allow_url_include = On
  • display_errors = On на боевом сервере
  • expose_php = On
  • Исполнение PHP разрешено в каталоге загрузок
  • composer install с dev-зависимостями
  • Старая версия PHP без обновлений безопасности
стало
  • allow_url_include = Off, allow_url_fopen по необходимости
  • display_errors = Off, ошибки пишутся в журнал
  • expose_php = Off
  • Загрузки вне корня сайта или с запретом исполнения скриптов
  • composer install --no-dev и проверка командой composer audit
  • Поддерживаемая версия PHP с актуальными патчами

Настройки — не панацея

Важно понимать ограничения. Директива disable_functions не защищает от выполнения произвольного PHP-кода, она лишь затрудняет запуск системных команд, и существуют способы её обхода. Поэтому её нужно сочетать с обновлениями, исправлением кода и минимальными правами для пользователя, от имени которого работает PHP.

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

План защиты PHP-проекта от RCE

  1. 01

    Составьте инвентаризацию: версия PHP, режим работы (FPM, CGI, mod_php), CMS, фреймворк, плагины, темы и все зависимости Composer.

  2. 02

    Обновите PHP до поддерживаемой ветки с актуальными исправлениями безопасности. Версии, снятые с поддержки, патчей не получают.

  3. 03

    Обновите CMS, плагины и библиотеки; удалите неиспользуемые. Для проектов на Composer регулярно запускайте composer audit.

  4. 04

    Уберите с боевого сервера всё лишнее: dev-зависимости, тестовые и установочные скрипты, резервные копии в веб-каталогах, файлы phpinfo.

  5. 05

    Проведите ревью кода: найдите вызовы eval, system, exec, shell_exec, passthru, popen, unserialize и include с переменными, затем замените их безопасными аналогами.

  6. 06

    Настройте php.ini и веб-сервер: disable_functions, open_basedir, запрет исполнения PHP в каталогах загрузок, закрытый доступ к служебным файлам.

  7. 07

    Ограничьте права: отдельный пользователь для каждого сайта, запись только в нужные каталоги, доступ к базе данных с минимальными привилегиями.

  8. 08

    Включите WAF и ограничение частоты запросов как дополнительный слой, а также резервное копирование с проверкой восстановления.

Мониторинг: как заметить проблему вовремя

Полностью исключить взлом невозможно, поэтому важно быстро его обнаружить. Настройте журналы веб-сервера и PHP, следите за изменениями файлов с помощью контроля целостности и регулярно сканируйте сайт антивирусом для серверов.

Используйте и инструменты поисковых систем. Яндекс Вебмастер и Google Search Console сообщают о проблемах безопасности, зараженном контенте и подозрительных страницах. Эти уведомления стоит включить сразу, а не искать их постфактум, когда трафик уже упал. Если подозрения подтвердились, не ограничивайтесь удалением найденного шелла: найдите точку входа, закройте её, смените все пароли и ключи и проверьте сервер на наличие других закладок.

чек-лист / признаки компрометации
Проверьте сервер: нет ли следов RCE
01
Новые PHP-файлыв каталогах загрузок, кэша и временных файлов
02
Изменённые файлыядра, тем и плагинов без вашего обновления
03
Подозрительные запросыв логах: длинные закодированные строки, имена системных команд в параметрах
04
Неизвестные задачи cronи новые пользователи ОС или администраторы CMS
05
Необъяснимая нагрузкана процессор и исходящие соединения на незнакомые адреса
06
Уведомленияоб угрозах в Яндекс Вебмастере и Google Search Console
Если вы подозреваете, что сервер уже скомпрометирован, не удаляйте следы сразу. Сохраните копию файлов и журналов для анализа, временно изолируйте сайт и только затем проводите очистку и смену всех доступов.

Итоги: как не допустить RCE в PHP

RCE — это не экзотика, а регулярная реальность для PHP-проектов: большинство атак использует давно известные ошибки, которые можно закрыть заранее.
  1. 01

    Держите PHP, CMS, фреймворк и зависимости в актуальном состоянии

  2. 02

    Никогда не передавайте пользовательский ввод в eval, оболочку, include и unserialize без строгой проверки

  3. 03

    Уберите с боевого сервера dev-зависимости, тестовые скрипты и отладку

  4. 04

    Настройте php.ini и веб-сервер по принципу минимальных привилегий

  5. 05

    Следите за журналами и уведомлениями Яндекс Вебмастера и Google Search Console

Безопасность PHP-проекта — это процесс, а не разовая настройка. Регулярные обновления, ревью кода и мониторинг обходятся несоизмеримо дешевле, чем восстановление после взлома. Если нужна независимая оценка, начните с аудита версий и конфигурации: именно там чаще всего находят самые опасные и самые легко устранимые проблемы.

Часто задаваемые вопросы

Проверьте свой PHP-сайт на уязвимости до того, как это сделают другие

Мы проведём аудит кода и конфигурации сервера и подготовим понятный план исправлений

Бесплатная первичная оценкаОтчёт с приоритетамиБез остановки сайта

RCE — самый критичный класс уязвимостей

Политика конфиденциальности

При оставлении заявки на ресурсе «https://gurucontext.ru» пользователи предоставляют следующие сведения:

  • Имя
  • Контактный телефон или Telegram
  • Адрес сайта пользователя (не обязательно)

Также администрация сайта получает данные об IP-адресе посетителей, типе браузера, времени нахождения на сайте и прочие подобные сведения через сервисы статистики.

Использование информации

Вся полученная информация используется администрацией «https://gurucontext.ru» исключительно в целях связи с клиентом.

Защита персональных данных

Компания «https://gurucontext.ru» обязуется не разглашать сведения, полученные от пользователей, и хранит их в защищённом виде.

Предоставление данных третьим лицам

Полученные сведения не передаются третьим лицам, за исключением случаев исполнения обязательств перед клиентом (с его разрешения) и обоснованных требований закона.

Контакты

Телефон: +7 (499) 955-47-00.
E-mail: info@gurucontext.ru.