php2shell-checker: два навыка от OpenAI для проверки уязвимости PHP
📂 Исходный код на GitHubРепозиторий от OpenAI: Node.js-скрипт phpcheck и два навыка для Codex (phpcheck-url и phpcheck-server), которые проверяют версию PHP по HTTP-заголовкам или через php -v и определяют, уязвима ли эта версия к php2shell по встроенной таблице пороговых версий.
OpenAI выложила репозиторий php2shell-checker. В нём лежит небольшой Node.js-скрипт и два навыка (skill) для Codex. Инструмент отвечает на один вопрос: уязвима ли версия PHP, которая обслуживает ваш сайт, к уязвимости php2shell. Проверить можно и удалённый сайт по URL, и локальный PHP-бинарник на своей машине.
Установить оба навыка в Codex можно одной командой:
$skill-installer install both skills from https://github.com/openai/php2shell-checker
В репозитории два навыка. phpcheck-url — когда у вас есть только адрес сайта. phpcheck-server — когда у вас есть доступ к самому серверу. Пример работы:
$phpcheck-url check https://example.com
$phpcheck-server check the PHP version serving my site
Зачем это нужно
PHP-сайты часто подставляют свою версию в HTTP-заголовки ответа. Заголовки Server и X-Powered-By можно прочитать обычным curl или браузером — без доступа к серверу. Если версия видна, её можно сравнить со списком уязвимых выпусков. Именно это и делает проверяющий скрипт.
php2shell — уязвимость в PHP. Репозиторий не описывает, как именно работает эксплойт. Он отвечает только за проверку номера версии: попадает ли он в уязвимый диапазон для своей ветки.
Что лежит в репозитории
phpcheck.js— точка входа для прямого запуска;phpcheck.test.js— тесты;skills/phpcheck-url/— навык для проверки по URL;skills/phpcheck-server/— навык для проверки на сервере.
Проверяющая логика живёт внутри навыка phpcheck-url, в файле scripts/phpcheck.js. Корневой phpcheck.js просто подключает этот же файл.
Прямой запуск без агента
Навык Codex не обязателен. Скрипт запускается напрямую через Node.js:
node phpcheck.js "https://example.com"
Проверка локального PHP:
node phpcheck.js --local
Доступные флаги из кода скрипта:
| Флаг | Что делает |
|---|---|
--json |
Вывод в формате JSON вместо текста |
--timeout SECONDS |
Таймаут запроса. По умолчанию 10 секунд, максимум 60 |
--local |
Проверить локальный PHP через php -v вместо URL |
--php PATH |
Путь к PHP-бинарнику для режима --local. По умолчанию php |
--version |
Показать версию самого скрипта (сейчас 1.0.0) |
--help |
Показать подсказку |
Задать одновременно URL и --local нельзя — скрипт выдаст ошибку и завершится с кодом 2. Такой же код возврата бывает при неверных аргументах: пустой URL, таймаут вне диапазона, логин или пароль в адресе, фрагмент после #.
Как читать результаты
| Результат | Код возврата | Значение |
|---|---|---|
OK |
0 | Стабильный патч-релиз выше встроенного порога для известной ветки |
VULNERABLE |
1 | Версия PHP равна порогу или ниже него |
UNKNOWN |
3 | Версии нет, ветка неизвестна, либо это более новый предрелиз |
В режиме --json возвращается объект с полями patch_status (ok, vulnerable или unknown), php_version, reason и exit_code.
Важно: коды 1 и 3 — это не сбой самого скрипта. Это ответы «уязвимо» и «неизвестно». Об этом отдельно напоминает навык phpcheck-url.
Пороговые версии
Версии уязвимы к php2shell в следующих диапазонах (данные из навыка phpcheck-server по состоянию на 20 октября 2026 года):
| Ветка PHP | Уязвимый диапазон (включительно) |
|---|---|
| 5.4 | 5.4.0 — 5.4.45 |
| 5.5 | 5.5.0 — 5.5.38 |
| 5.6 | 5.6.0 — 5.6.40 |
| 7.0 | 7.0.0 — 7.0.33 |
| 7.1 | 7.1.0 — 7.1.33 |
| 7.2 | 7.2.0 — 7.2.34 |
| 7.3 | 7.3.0 — 7.3.33 |
| 7.4 | 7.4.0 — 7.4.33 |
| 8.0 | 8.0.0 — 8.0.30 |
| 8.1 | 8.1.0 — 8.1.34 |
| 8.2 | 8.2.0 — 8.2.34 |
| 8.3 | 8.3.0 — 8.3.35 |
| 8.4 | 8.4.0 — 8.4.26 |
| 8.5 | 8.5.0 — 8.5.11 |
Эта же таблица зашита в код скрипта в виде объекта VULNERABLE_THROUGH. Ветки, которых в списке нет, проверяющий считает неизвестными, пока сообщение о безопасности не подтвердит их статус.
Как скрипт работает внутри
Для URL скрипт делает запрос HEAD. Только если сервер отвечает кодами 405 или 501, он повторяет запрос через GET. Заголовки Server и X-Powered-By складываются в одну строку, из неё регулярным выражением вытаскивается номер версии вида PHP/8.3.15.
В режиме --local скрипт запускает php -v и парсит строку вида PHP 8.3.15 (...). Ответ может содержать предупреждения на старте — это учитывается.
Если в ответе нашлось несколько упоминаний PHP, правило простое: статус vulnerable всегда перебивает остальные. Баннер с версией OK не может скрыть уязвимую или неизвестную версию, найденную рядом.
Сборки с метками dev, alpha, beta или rc скрипт помечает как unknown. Предрелиз следующего патча — не доказательство того, что стабильный фикс уже вышел.
Чего инструмент не делает
Авторы честно описывают ограничения. Их важно знать, чтобы не получить ложное спокойствие.
- Скрипт смотрит только на версию из HTTP-заголовков или из вывода
php -v. Больше он ничего не анализирует. - Он не следует за редиректами и не читает тело ответа.
- Если заголовки скрыты или изменены, результат будет
UNKNOWN. OK— это сравнение номеров. Скрипт предполагает, что любой более новый стабильный патч в той же ветке содержит фикс. Он не проверяет наличие фикса напрямую.- Вендоры (Red Hat, Debian и другие) часто переносят патчи безопасности в старые номера версий и не меняют номер, который виден снаружи. Поэтому
UNKNOWNне означает, что цель защищена. И наоборот:OKпо номеру не гарантирует, что патч реально применён. - Единственные по-настоящему надёжные проверки — это запущенная сборка PHP и официальные сообщения о безопасности от PHP и от вашего вендора. Настройки конфигурации сами по себе ничего не доказывают.
Навык phpcheck-server задаёт агенту тот же настрой: сначала php -v, потом сверка с тем PHP-FPM или Apache, который реально обслуживает сайт. Если проверить запущенную версию не удалось — агент должен сообщить unknown, а не угадывать. Запускать эксплойты для проверки запрещено.
Навык phpcheck-url добавляет: для голого хоста используйте HTTPS. Результат по заголовкам — менее сильное доказательство, чем проверка версии и пакета прямо на сервере.
Тесты
Тесты запускаются штатным раннером Node.js:
node --test phpcheck.test.js
Тесты поднимают локальные HTTP-серверы и подставляют поддельный PHP-бинарник. Установленный PHP и доступ к реальным сайтам не нужны.
Лицензия и участие
Лицензия — Apache License 2.0. OpenAI не принимает внешний код в этот проект, но принимает отчёты об ошибках и обратную связь через GitHub issues. Подробности — в CONTRIBUTING.md.
Итог
php2shell-checker — тонкий инструмент с чёткой границей ответственности. Он сравнивает номер версии PHP с встроенной таблицей и честно говорит «не знаю», когда данных недостаточно. Для агента Codex это два навыка: один читает заголовки по URL, другой работает на сервере. Для всех остальных — обычный node phpcheck.js. Финальное решение о том, обновлять PHP или нет, остаётся за вами и за официальными сообщениями о безопасности от PHP и вашего вендора.