php2shell-checker от OpenAI полезен для первичной проверки, но сам по себе не доказывает безопасность сервера. Инструмент сравнивает версию PHP, полученную из HTTP-заголовков или через php -v, с заданными порогами исправлений. Поэтому скрытый заголовок может дать результат UNKNOWN, а backport-патч от дистрибутива — заставить исправный сервер выглядеть уязвимым.
Сначала разберитесь со статусами
Официальный репозиторий OpenAI использует три основных статуса. Это сигналы для первичной сортировки, а не полноценная оценка уязвимости.
| Результат | Код выхода | Что означает | Что делать дальше |
|---|---|---|---|
OK | 0 | Распознанная ветка достигла минимальной исправленной версии или находится выше неё | Проверить, что PHP-процесс, обслуживающий веб-трафик, использует именно эту версию |
VULNERABLE | 1 | Обнаруженная версия ниже минимальной исправленной версии | Обновить runtime, обслуживающий сайт, перезапустить его воркеры и повторить обе проверки |
UNKNOWN | 3 | Инструмент не смог определить распознанную версию или получить подходящий ответ | Проверить сервер локально и не считать его исправленным |
| Некорректные аргументы | 2 | Сама команда указана неверно | Исправить команду и запустить её снова |
Что именно выпустила OpenAI
В публичном репозитории php2shell-checker находятся Node.js-скрипт, тесты и два навыка Codex: phpcheck-url для доступного по сети сайта и phpcheck-server для сервера, к которому у вас есть доступ. Инструмент собирает сведения о версии, но не эксплуатирует цель и не сканирует код приложения.
Выбирайте режим проверки под задачу
Проверка публичного URL
Клонируйте или скачайте репозиторий, затем запустите Node.js-скрипт для нужного сайта:
node phpcheck.js "https://example.com"
При удалённой проверке отправляется HTTP-запрос HEAD. На GET инструмент переходит только если сервер отвечает кодом 405 или 501. Проверяются заголовки X-Powered-By и Server; перенаправления не обрабатываются, содержимое ответа не анализируется.
CDN, reverse proxy, настройка expose_php=off или нестандартная конфигурация сервера могут удалить версию PHP ещё до того, как ответ попадёт в checker. Результат VULNERABLE означает, что систему нужно обновить; отсутствие заголовка требует локальной проверки.
Проверка локального PHP-бинарника
На машине с установленным PHP используйте:
node phpcheck.js --local
Команда запускает php -v для бинарника, который находится в текущем PATH. Это не доказывает, что тот же бинарник обслуживает сайт: на одном хосте могут отдельно использоваться CLI, PHP-FPM, CGI, модуль Apache, контейнер или сборка из исходников.
После локальной проверки определите runtime, подключённый к веб-серверу. В контейнерной инфраструктуре смотрите на запущенный контейнер, а не только на тег его образа. Если PHP установлен из пакета, проверьте нужный пул PHP-FPM или модуль Apache, а также changelog пакета от поставщика.
Установка и использование навыков Codex
В официальном README оба навыка устанавливаются одной командой Codex:
$skill-installer install both skills from https://github.com/openai/php2shell-checker
После этого выберите интерфейс, соответствующий вашему уровню доступа:
$phpcheck-url check https://example.com
$phpcheck-server check the PHP version serving my site
Codex использовать необязательно. Для CI-задач и минимальных хостов достаточно прямого запуска Node.js-команды. В автоматизации добавьте --json: поле patch_status вернёт ok, vulnerable или unknown, и скрипту не придётся разбирать текстовый вывод терминала.
Проверка скачанного checker
В репозитории используется встроенный тестовый runner Node:
node --test phpcheck.test.js
Набор тестов проверяет CLI через локальные HTTP-серверы и использует поддельный PHP-исполняемый файл для локальных сценариев. Согласно README, для запуска не нужны ни настоящая установка PHP, ни доступ к внешнему сайту.
Считайте UNKNOWN результатом для отладки
UNKNOWN означает, что данных недостаточно. Сайт может скрывать версию PHP, использовать нераспознанную ветку, не отвечать или работать на более новой предварительной версии. Ни один из этих вариантов не подтверждает наличие исправления.
Пользователь @jvr0x кратко описал ограничение так:
«Это всего лишь сравнение версии с порогами от 20 октября, поэтому скрытые заголовки дают UNKNOWN».
Удалённая команда видит HTTP-ответ, но не процесс за reverse proxy. Если заголовок скрыт, нужно проверять сервер, а не бесконечно повторять запросы к URL.
После UNKNOWN действуйте по следующей схеме:
- Запустите
node phpcheck.js --localна хосте, который обслуживает сайт. - Определите, куда попадает запрос: в PHP-FPM, CGI, Apache
mod_phpили контейнер. - Проверьте changelog пакета от поставщика на наличие backport-патчей.
- После обновления перезапустите нужные воркеры PHP-FPM или Apache.
- Проверяйте именно путь, обслуживающий сайт, а не только бинарник
phpпо умолчанию в shell.
Без SSH проверка URL может быть единственным вариантом для первого прохода. Если shared-хостинг скрывает версию в заголовке, провайдер должен подтвердить runtime, обслуживающий сайт, ревизию пакета и факт перезапуска.
Одной таблицы версий для решения недостаточно
Checker считает минимальными исправленными upstream-релизами для соответствующих веток PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35. Официальные тесты подтверждают: 8.4.26 получает статус VULNERABLE, а 8.4.27 — OK. Сам PHP называет 8.5.12, 8.4.27, 8.3.36 и 8.2.35 релизами безопасности.
| Ветка | Минимальный исправленный upstream-релиз | Предыдущий релиз, признанный уязвимым |
|---|---|---|
| PHP 8.5 | 8.5.12 | 8.5.11 |
| PHP 8.4 | 8.4.27 | 8.4.26 |
| PHP 8.3 | 8.3.36 | 8.3.35 |
| PHP 8.2 | 8.2.35 | 8.2.34 |
| Ситуация при развёртывании | Почему простое сравнение версий может ввести в заблуждение | Какие данные использовать |
|---|---|---|
Скрытый заголовок X-Powered-By или Server | Удалённый checker не может определить PHP | Локальная инвентаризация runtime |
| Пакет безопасности Debian или Ubuntu | Поставщик мог добавить исправление в старую upstream-версию, не меняя её номер | Рекомендации поставщика и changelog пакета |
| PHP-FPM и CLI на одном хосте | php -v может описывать CLI, а не HTTP-воркер | Конфигурация веб-сервера и FPM |
| Закэшированный контейнер или закреплённый digest | Тег в registry может быть актуальным, пока запущенный контейнер остаётся старым | ID образа и версия запущенного контейнера |
| Воркеры Apache или FPM не перезапущены | Исправленные файлы уже находятся на диске, но старые воркеры всё ещё работают | Время запуска процесса и проверка после перезапуска |
| Неподдерживаемая ветка или prerelease | Checker может не распознать состояние патча от поставщика | Уведомление безопасности PHP или поставщика |
В разделе ограничений репозитория сказано, что инструмент предполагает наличие исправления в более поздних стабильных патч-релизах перечисленной ветки и не может самостоятельно проверить сам факт исправления. Дистрибутив способен выпустить security backport, не меняя upstream-номер версии, поэтому его changelog надёжнее, чем одно только отображаемое число.
Обновление WordPress, Drupal, Laravel или другого PHP-приложения не исправляет сам движок PHP. Обновите пакет или образ runtime, перезапустите воркеры и проверьте процесс, принимающий веб-запросы.
FAQ
Какой результат позволяет закрыть задачу по устранению проблемы в production?
Ни один результат не должен закрывать задачу сам по себе. Статус OK нужно сопоставить с используемым SAPI, статусом backport-патча от поставщика, всеми нужными vhost и контейнерами, а также подтверждением, что после обновления воркеры были перезапущены.