«Столица швейных машин» (shveichel.ru) работает с 1995 года. На сайте тысячи товаров, оформление заказов, оплата и кредит. Взлом такого магазина — это не только чужая надпись на главной. Это заказы, телефоны и адреса покупателей, данные об оплате. Поэтому ответа «версию PHP обновили» нам было мало: мы хотели знать, что ещё открыто из интернета.
Что такое PHP2Shell и почему это касалось магазина
PHP2Shell — это две критические уязвимости в PHP, языке, на котором работает 1С-Битрикс, а вместе с ним WordPress, Joomla и большинство сайтов на готовых движках. Через них чужой человек может запускать на сервере сайта свои команды. Пароль и доступ к админке ему не нужны: атака срабатывает раньше, чем включается сам сайт.
Исправление вышло 21 октября. Попытку атаки специалисты заметили ещё 17-го, а 26 октября американское агентство CISA добавило обе уязвимости в список тех, что используют в реальных атаках. Из-за этой угрозы в Нидерландах, Финляндии и Франции отключали государственные сайты.
Обновить 1С-Битрикс здесь мало: обновится сайт, но не PHP на сервере. Закрывает дыру только исправленная версия самого PHP. Подробнее о том, кто её ставит и что делать со старыми версиями, мы писали в отдельном разборе.
Главная дыра уже была закрыта
Первое, что мы проверили, — версию PHP, на которой работает сам магазин. Не ту, что показывает сервер в командной строке, а ту, что обрабатывает запросы посетителей. Это разные вещи: в панели хостинга версию выбирают для каждого сайта отдельно.
Хорошая новость: хостинг сам поставил исправленную версию PHP 8.3.36 23 октября. Магазин был открыт для этой атаки примерно два дня.
Мы закрыли ещё одну, третью уязвимость PHP, о которой сообщили 23 октября и для которой исправления пока нет. Магазин и так был к ней не уязвим из-за своих настроек, но разработчики PHP советуют выключить функцию, через которую она работает. Магазину эта функция не нужна, и мы её выключили одной строкой, проверив, что загрузка файлов и всё остальное работают.
На этом можно было закончить. Мы продолжили.
Что ещё было открыто из интернета
Мы просмотрели всё, что лежит в открытой папке сайта, то есть всё, что можно открыть по прямой ссылке. Обновление PHP ничего из этого не закрывает.
| Что нашли | Чем это грозило | Что сделали |
|---|---|---|
Служебные скрипты запускались по прямой ссылке. Один из них, teset.php, обнулял остаток товара, другой запускал импорт | Любой мог сделать товар «закончившимся» для покупателей или запустить импорт каталога | Закрыли доступ из интернета; по расписанию скрипты работают как раньше |
| Редактор базы данных Search-Replace-DB открывался любому посетителю | Паролей от базы в нём не было, но если пароль когда-нибудь утечёт, инструмент для порчи данных уже стоит на сайте | Убрали из открытой папки |
45 копий файлов с окончаниями вроде .bak и .php_old | Сервер отдавал их как текст: любой мог прочитать, как сайт устроен изнутри | Закрыли доступ. Паролей и ключей в проверенных копиях не нашли |
Служебная программа разработчиков composer.phar | Запускалась по ссылке и показывала путь к сайту на сервере | Убрали из открытой папки |
Список библиотек: composer.json, composer.lock, папка vendor | Готовая шпаргалка для того, кто ищет уязвимости | Закрыли доступ |
| Неустановленный модуль импорта, лежавший в папке сайта | Именно его искали сканеры взломщиков: 60 срабатываний защиты за октябрь | Убрали из открытой папки |
Ничего не удалили: всё, что убрали, сохранено вне открытой папки, чтобы можно было вернуть. Перед тем как закрыть скрипты, мы проверили, что от них ничего не зависит: расписание запускает их из командной строки, а ни одна страница сайта на них не ссылается.
Скрипт с опечаткой в имени, teset.php, судя по всему, написали когда-то для проверки и забыли. Так обычно и появляются такие находки: никто их не прятал, просто никто о них не помнил.
Обходной путь через соседний сайт
Самая опасная находка была за пределами магазина. На том же аккаунте хостинга работает ещё один сайт, и на день проверки у него был PHP 7.1. Для такой старой версии разработчики PHP исправлений не выпускают, а подтверждения, что хостинг её исправил, мы тогда не нашли.
Хостинг запускает оба сайта от имени одного и того же пользователя. На практике это значит, что программа на соседнем сайте видит файлы магазина как свои: может прочитать пароль от его базы данных и переписать его код. Мы это проверили, а не предположили. Получи кто-то управление соседом через PHP2Shell, он получил бы и магазин, несмотря на свежий PHP у самого магазина.
На день проверки на сервере нашлось три версии PHP: 8.5 — в командной строке, где работают администраторы, 8.3 — у магазина, 7.1 — у соседа. Спросите «какая у нас версия PHP?» — и честный ответ «8.5» ничего не скажет о том, что видят посетители каждого сайта.
Сами переключить версию у соседа мы не могли: панель хостинга просит код из почты владельца. Поэтому мы пошли через поддержку хостинга. Хостинг обновил PHP и выпустил исправления безопасности сам, а мы после этого проверили результат. Обходного пути к магазину больше нет.
Модуль, который нельзя было удалять
За 26,5 часа журнал ошибок магазина набрал 18 347 записей, и 18 294 из них дал один и тот же модуль: примерно 700 в час. Судя по названию со словом Metrika, он что-то считал для аналитики.
Модуль, который только шумит, проще всего выключить. Прежде чем это делать, мы посмотрели, за что он отвечает, и название оказалось обманчивым: через модуль работает покупка в кредит банка. За год так оформили 13 заказов, последний — 2 октября. Выключив его, мы получили бы чистый журнал и магазин без кредита, причём при редкой оплате пропажу могли бы не заметить долго. Ошибки давал старый код, несовместимый с PHP 8. Мы поправили его, кредит остался, ошибок стало ноль.
В том же модуле нашлась и настоящая дыра. Служебный файл модуля вызывал любую функцию PHP, имя которой приходило в запросе, если запрос шёл от вошедшего администратора, и не проверял, что администратор отправил его сам. Теперь модуль принимает только три нужных ему действия и требует проверочный ключ сессии.
Когда шум ушёл, стал виден другой сбой. В каталоге 415 разделов, 167 из них скрыты, и по их адресам открывалась ошибка сервера, а не страница «не найдено». В карте сайта для поисковиков этих адресов нет, но покупатель со старой закладкой видел сломанную страницу. Теперь такие адреса отвечают обычной страницей 404.
Следов взлома нет, но мы говорим, чего не видели
Мы проверили всё, что изменилось на сайте с 15 октября, ещё до объявления об уязвимости: файлы, администраторов, фоновые задачи, ключи доступа к серверу, расписание. Подозрительного не нашлось.
Но журналов запросов к сайту за 21–23 октября через наш доступ нет. А если данные просто скопировали, файлы остаются прежними, и такая проверка этого не покажет. Поэтому мы говорим «следов не нашли», а не «взлома не было». Подрядчик должен называть не только то, что проверил, но и то, чего проверить не смог.
Две тревоги оказались ложными. Магазин выглядел медленным, но цифру испортил сам замер с нашей машины: у реальных посетителей сервер отвечает за 0,67 секунды. А 60 срабатываний защитного фильтра оказались фоновым сканированием, которое не попало в цель.
Магазин работает, продажи идут
После правок мы проверили то, ради чего магазин существует:
- 60 случайных страниц из карты сайта — все открываются;
- главная, каталог, корзина, контакты, оплата — работают;
- путь от товара до оформления заказа в браузере — проходит, форма заказа и способы оплаты на месте;
- вход в админку — работает;
- с 26 по 31 октября, уже на новом PHP, прошло 5 заказов с оплатами; все 34 письма магазина с 17 октября отправлены.
Что даёт сопровождение
Эта работа — не разовая услуга «проверить на вирусы». Так выглядит сопровождение сайта, когда приходит новость об уязвимости:
- Понять, касается ли она именно вашего сайта, а не «серверов вообще».
- Проверить не только громкую дыру, но и то, что рядом: забытые скрипты, копии, инструменты, соседние сайты.
- Ничего не сломать: перед каждой правкой проверить, что от этого зависит, после — что продажи идут.
- Честно сказать, что проверено, а что нет.
Мы сопровождаем сайты на 1С-Битрикс, проверяем и лечим взломанные сайты. Если вы не уверены, что ваш сайт закрыт от PHP2Shell, напишите нам через форму под статьёй.
Для технических специалистов
Уязвимости и версии
CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) и CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), CVSS 4.0 — 9.2 у каждой. Исправлены в 8.5.12, 8.4.27, 8.3.36 и 8.2.35, бюллетень PHP от 21 октября. Наибольший риск — у mod_php: запрос атакует до выполнения кода приложения. Для 8.1 и старше официальных сборок нет; команда PHP опубликовала исправления исходников только для 7.4, 8.0 и 8.1.
| Сайт на аккаунте | PHP для веба | SAPI | Исправление |
|---|---|---|---|
| shveichel.ru | 8.3.36 | apache2handler | Исправленный выпуск |
| Соседний сайт | 7.1.33 на 31.10 | apache2handler | Обновлён хостингом |
| Командная строка | 8.5.12 | CLI | Не обращена в сеть |
Пакет php83-php установлен хостингом 23.10 в 12:47 (rpm -qa --last). На 31.10 для 7.1 упоминаний CVE в журнале изменений пакета не было, в отличие от сборок 5.6, 7.4, 8.0 и 8.1 на том же сервере. После обращения в поддержку хостинг обновил PHP у соседнего сайта сам; результат мы проверили. Проверка с соседнего сайта: is_readable для bitrix/.settings.php магазина и is_writable для bitrix/ вернули true.
CVE-2026-115560
Раскрыта 23.10, исправлением октябрьских выпусков не закрыта. Требует session.serialize_handler в php_binary или php_serialize с переключением на php во время работы и включённого session.upload_progress. У магазина serialize_handler=php, переключений нет — уязвимость недостижима. Тем не менее добавили в .htaccess по рекомендации PHP:
php_flag session.upload_progress.enabled off
Проверка: составной POST с PHP_SESSION_UPLOAD_PROGRESS к скрипту без сессии до правки создавал файл сессии, после — нет. Загрузка файлов работает. 40 параллельных запросов — оба рабочих процесса на 8.3.36 с progress=0. Строка привязана к mod_php: при переходе на FPM её нужно убрать, иначе Apache ответит 500.
Закрытие открытой папки
RewriteRule ^(vendor|local/(php_interface|cron|config|logs|scripts))(/|$) - [F,L,NC]
Плюс FilesMatch расширен на composer.(json|lock), phar, bak[-._].*, php[-._~].*. Блокировку проверяли несуществующими именами, чтобы не запустить настоящий скрипт. Search-Replace-DB, composer.phar и неустановленный esol.importexportexcel 3.1.8 перенесены в карантин вне корня сайта.
Модуль кредита
Обработчик customizePaymentBlock был нестатическим, а ExecuteModuleEventEx проверяет is_callable([класс, метод]), что на PHP 8.3 даёт false — отсюда поток исключений. После исправления проверили все 743 зарегистрированных обработчика классов: нестатических не осталось. В ajax.php модуля call_user_func($_REQUEST["ACTION"]) заменён списком разрешённых действий (checkStatus, cancel, approve) и check_bitrix_sessid(); до правки phpinfo выполнялся для сессии администратора без токена.
Неактивные разделы
Шаблон Aspro строил разметку раздела до собственной проверки if($section), поэтому ветка process404 была недостижима и неактивные разделы отдавали 500. Обёртка if($section) вокруг вызова вернула 404. Правка затрагивает шаблон производителя — после обновления Aspro её нужно проверить.
Проверка на следы взлома
Поиск по ctime (не mtime, который подделывается) с 15.10 для *.php, *.phtml, *.phar, .htaccess*, .user.ini, *.pl, *.cgi вне кешей: только два сгенерированных фида. В upload/ нет исполняемого кода и двойных расширений. Администраторы: 16 в группе 1, новых с 01.01.2026 нет. Агенты: 71, подозрительных нет. authorized_keys и crontab без изменений. Журналы веб-сервера по SSH недоступны, поэтому окно 21–23.10 не просмотрено.
Вопросы и ответы
Если хостинг обновил PHP, сайт защищён от PHP2Shell?
От самой PHP2Shell — да, если обновлена версия, на которой работает именно сайт, а не командная строка. Проверьте и соседние сайты на том же аккаунте: старый сосед может открыть доступ ко всем.
Как узнать версию PHP у своего сайта?
Спросите хостинг или подрядчика: «Какая версия PHP у сайта для посетителей, не в командной строке? Установлено ли исправление CVE-2026-109618 и CVE-2026-109619?» Если версия ниже 8.2, официального выпуска PHP с исправлением для неё нет.
Обновление 1С-Битрикс закрывает PHP2Shell?
Нет. Обновление Битрикса обновляет сайт, а уязвимость в PHP на сервере. Нужно обновить PHP.
Почему нельзя было просто удалить модуль, который сыпал ошибками?
Это был модуль кредита банка, через который прошло 13 заказов за год. Удаление убрало бы ошибки и тихо выключило бы способ оплаты. Сначала нужно понять, что делает модуль, и только потом решать.
Что спросить у подрядчика после такой новости?
Какая версия PHP у сайта, а не у сервера. Какие ещё сайты живут на этом аккаунте и на какой они версии. Что из служебного открывается из интернета. Что проверили на следы взлома и чего проверить не смогли.