Восстановление 1С-Битрикс после взлома: почему сайт прожил год без трёх файлов и внезапно перестал открываться
Три файла на сайте 1С-Битрикс были удалены ещё в апреле 2025 года, но сайт продолжил работать — готовые HTML-страницы отдавал композитный кэш. Наиболее вероятная причина, по которой проблема проявилась только через 16 месяцев после удаления файлов: пока страницы отдавались из готового HTML, отсутствующие PHP-файлы не загружались. После очистки или пересборки кэша Битрикс снова начал выполнять PHP-код и обнаружил отсутствие CKraken.php. После компрометации отсутствовали: класс модуля, обработчик инфоблоков и файл подключения стилей и скриптов. Бэкапы хостинга не содержали нужных файлов, лицензия истекла, апдейтер заблокирован. Работоспособность сайта удалось восстановить за один рабочий день: вернули ядро с другой установки, добыли архив версии 3.0.2 (2020 год) и совместили его с текущей версией. Ниже — полный разбор: что пропало при взломе, как это вычислить и как поднять сайт, когда бэкапов нет.
При первой компрометации признаков установки постоянного шелла или кражи данных обнаружить не удалось — судя по логам и датам изменения файлов, во время компрометации были удалены три файла: класс модуля Кракен (CKraken.php), обработчик инфоблоков (iblock.php) и styles_and_scripts.php — файл, который подключает стили и скрипты шаблона concept_kraken_s1. Сайт упал с fatal error «Class CKraken not found» в августе 2026-го — хотя трёх файлов не было уже больше года: всё это время страницы отдавал композитный кэш. Бэкапы хостинга не содержали нужных файлов, а лицензия Битрикс истекла ещё в июне 2025-го. Продление лицензии за 1800 ₽ не дало доступа к архиву модуля — маркетплейс умеет только обновлять установленный модуль, а это уже 18 000 ₽. Восстановление заняло один день: диагностика по датам файлов, сброс пароля админа через БД, iblock.php из другого своего проекта, добыча архива версии 3.0.2 (2020 год) в открытых источниках (за три рабочих дня ответа от автора не последовало) и хирургический патч старой версии под PHP 8.1.
Почему удаление файлов проявилось только через год
30 апреля 2025-го с сервера пропали три файла — в том числе CKraken.php, ядро модуля Кракен, которое грузится на каждом хите: без него не работает ни шаблон, ни инфоблоки, ни меню. Но сайт не упал: композитный кэш продолжал отдавать готовые HTML-страницы. В данном случае сайт не изменялся, поэтому страницы кэша использовались больше года — срок жизни композитного кэша не фиксирован, он хранится, пока страницы не пересоберут и кэш не очистят. Белый экран с Fatal error: Class "CKraken" not found появился в августе 2026-го, после очистки или пересборки кэша.
Владелец написал на хостинг, ему сказали «проблема в коде». Фирма, которая делала сайт, за год работы развалилась, исходники никто не отдал. Хостинг предложил откат из бэкапа — но в бэкапах лежала только база данных и статический контент, файлов модуля там не было. При этом сайт продолжал открываться: страницы отдавал композитный кэш. В феврале 2026-го через старую дыру в модуле landing прошла вторая атака — хостинг чистил сайт от лоадеров и шеллов, но удалённые файлы так и не вернул, и сайт снова «заработал» из кэша. Владелец говорил, что сайт вроде работает — так и было. После очистки или пересборки композитного кэша Битрикс снова попытался загрузить отсутствующий CKraken.php, и сайт перестал открываться. Вроде и хостинг живой, и БД на месте, а открыть нельзя.
Разбор занял час. По датам модификации файлов (mtime) и логам хостинга картина восстановилась полностью: удаление произошло 30.04.2025 в один заход, с правами доступа к файловой системе сайта. Отдельный вопрос — почему сайт упал только в августе 2026-го: ответ нашёлся в композитном кэше: страницы жили больше года, пока их не очистили или не пересобрали.
Три файла:
bitrix/modules/concept.kraken/classes/general/CKraken.php (класс модуля, исходник ~376 КБ), bitrix/php_interface/iblock.php (обработчик инфоблоков) и bitrix/templates/concept_kraken_s1/styles_and_scripts.php (подключение CSS и JS шаблона). Всё остальное — БД, ядро Битрикс, каталог — не тронуто. Судя по найденным следам, основной целью было вывести сайт из строя, а не похитить данные: доступ был полным, но признаков кражи данных обнаружить не удалось.Шаг 1. Диагностика: найти, что именно пропало
Когда Битрикс падает, первым делом смотрим bitrix/php_interface/init.php, логи и тайминги файлов (для WordPress аналогичный сценарий разобран в статье про белый экран смерти). Я начал с вопроса: что изменилось в день падения? На шаред-хостинге Sprinthost доступ по SSH есть, но проще работает FTP-клиент с отображением дат.
# по mtime ищем файлы, изменённые/удалённые 30.04.2025
find /home/example/public_html/bitrix -newermt "2025-04-29" ! -newermt "2025-05-01" -printf "%p %TY-%Tm-%Td %TH:%TM\n"
Дальше — сверка с бэкапом. На Sprinthost бэкапы лежат в панели, откат точечный: только база или только файлы. В файловом бэкапе модуля concept.kraken не оказалось вообще — он либо не попал в архивацию, либо попал уже после удаления. На других хостингах нюансы свои: на Beget бэкапы хранятся 14 дней в панели, на Timeweb — в разделе «Бэкапы» со своими копиями баз и файлов, на Reg.ru файловые копии делаются по расписанию тарифа. Проверяйте содержимое бэкапа, а не только дату: файлы модуля могли просто не войти в архив.
Если бы владелец держал копию модуля отдельно (скачанный zip из маркетплейса или архив с хостинга прошлых лет), восстановление заняло бы час. Вместо этого пришлось искать дистрибутив по всему интернету. Резервная копия модуля — это файл на 5 МБ, который стоит хранить рядом с сайтом всегда.
Шаг 2. Вернуть доступ в админку: сброс пароля через БД
Пароль админа никто не помнил, а вход нужен был хотя бы чтобы посмотреть статус лицензии. Битрикс хранит пароли в таблице b_user, колонка PASSWORD — хэш в формате crypt (обычно SHA-512 с солью, $6$...). Пароль можно перегенерировать прямо в БД.
# генерим хэш SHA-512 crypt на любой машине с python3
python3 -c "import crypt; print(crypt.crypt('novyj-parol-32-simvola', crypt.mksalt(crypt.METHOD_SHA512)))"
# результат вида $6$Q2kT9xL0$vh3K0qWYOP5BQmcD8E1Z... — вставляем в БД
UPDATE b_user SET PASSWORD='$6$Q2kT9xL0$...', CHECKWORD='', LOGIN_ATTEMPTS=0 WHERE LOGIN='admin';
Сбрасываем пароль только с ведома владельца и только через SSH/панель хостинга, не через скрипт на сайте. После восстановления — сменить пароль в админке на новый и включить 2FA. Если логин админа не admin — найти его запросом
SELECT ID, LOGIN, NAME FROM b_user WHERE ACTIVE='Y';.Шаг 3. Восстановить файлы, которых нет нигде
С ядром Битрикс повезло: iblock.php оказался идентичным файлу с другого моего проекта на той же версии Битрикс. Версия на сервере — 23.300.100. Взял оттуда, сверил контрольной суммой и положил на место.
sha256sum /home/example/public_html/bitrix/php_interface/iblock.php
# сверяем с эталоном с другой установки той же версии
# права: 644, владелец тот же, что у соседних файлов
С модулем Кракен так не вышло. Класс CKraken.php в открытом виде нигде не лежит: модуль продавался через маркетплейс Битрикс и завязан на лицензию. Лицензия истекла 6 июня 2025 года — через месяц после взлома, а последнее обновление на сайте было ещё раньше, 6 июня 2024-го. Апдейтер модуля при любой попытке ругался:
# ошибка апдейтера на странице обновлений
SYS_ERROR_AB_ACTIVE: обновление недоступно, лицензия не активна
# в БД это видно так:
# b_option: update_system_check = 03.08.2026, update_system_update = 06.06.2024
Админка → Настройки → Инструменты → Правила модулей → «Ключ лицензии». Или по БД: таблица
b_option, параметры update_system_check (последняя проверка) и update_system_update (последнее обновление). Если update_system_update старше года — обновлений давно не было, апдейтер будет ругаться на лицензию при любой попытке.Шаг 4. Добыть дистрибутив модуля
Модуль Кракен живой и поддерживается, но архив его файлов маркетплейс не отдаёт — скачать модуль нельзя в принципе, доступно только «обновить» уже установленный. Сначала попробовали официальный путь: владелец продлил лицензию Битрикс за 1800 ₽. Но тут выяснилась подлость: продление дало только сам ключ лицензии. Архив модуля так и не появился, а кнопка обновления требует продления уже по другому тарифу — 18 000 ₽. За 1800 ₽ архив не получить.
Написал автору модуля с просьбой выслать файлы напрямую — за три рабочих дня ответа так и не было, ждать дальше смысла не было. Официальный путь закрылся, остались неофициальные источники: форумы веб-мастеров и открытые архивы. В открытых источниках удалось найти архив версии 3.0.2 (2020 год). Оттуда и взяли исходник — уже вниз по течению, когда стало понятно, что его придётся подгонять под работающий сайт.
Тянем файлы из таких архивов только для восстановления собственного сайта, где модуль уже был легально куплен. Проверяем каждый файл на подозрительный код: обфусцированные eval, base64-блоки, подозрительные include. Свежие нуллед-дистрибутивы из сомнительных групп — риск получить второй шелл. Архив 2020 года в этом смысле безопаснее свежих сборок.
Шаг 5. Хирургический патч: старая версия против новой
Вот тут началось самое интересное. На сайте стояла версия модуля 3.6.10. В архиве — 3.0.2 (2020 год). Файлы нельзя положить как есть: в новой версии классы разнесены по отдельным файлам и грузятся автозагрузкой, в старой — все классы свалены в один CKraken.php. На сервере лежал только этот один файл, и внутри него оказалось полтора десятка классов: CKrakenDB, CKrakenHost, CKrakenSearch, CKrakenCurrencies и другие.
Правильная стратегия: не заливать целиком, а взять из архива только то, чего нет на сервере, и адаптировать под текущую версию. Мой план был такой:
- из архива вытащить
classes/general/CKraken.php(в нём основной класс CKraken); - вырезать из файла классы-дубли, которые в версии 3.6.10 живут отдельными файлами (CKrakenDB, CKrakenHost, CKrakenSearch и остальные) — оставить только
class CKraken; - сравнить метод за методом с текущей версией, добавить недостающие методы;
- прогнать
php -lи залить.
Первый прогон с полным файлом упал именно на классе-дубле: CKrakenDB::CKrakenDBval() вызывался статически, а сам метод статическим не был. После вырезки лишних классов и заливки только основного CKraken ошибка ушла — но вылезла следующая, уже в самом классе.
На сервере PHP 8.1 — а это самое больное место. Код 2020 года писался под PHP 5/7 и при первом же запуске упал по-новому:
Fatal error: Non-static method CKraken::os() cannot be called statically
В PHP 8 вызов нестатического метода статически — фатальная ошибка, а не предупреждение. В классе CKraken нашлось 13 таких методов, вызываемых в шаблоне статически: os, admin_setting, admin_setting_custom, buttonEditAttr, buttonEditClass, ClearCacheIBCatalog, CreateSoc, getTermination, IsConstructor, Krakenhex2rgb, Krakenrgb2hex, krakenMenuAttr, krakenMenuClass. Лечится одной правкой — объявить их public static: методы не использовали $this, поэтому статическими их делать безопасно.
// было: public function os()
// стало: public static function os()
Параллельно добавил два метода, которые появились в 3.6.10 и которых нет в старой версии: prepareText (экранирование вывода — htmlspecialchars) и isAdmin (проверка прав). Без них шаблон падал на 500 в админке и местами в публичке.
# проверка синтаксиса до заливки
php -l CKraken.php
# PHP Parse error → no syntax errors detected
Шаг 6. Восстановить файл шаблона
Вместе с классом модуля был удалён styles_and_scripts.php — файл, который собирает и подключает стили и скрипты шаблона concept_kraken_s1. Шаблон падал на каждом хите: Failed opening required styles_and_scripts.php. Этого файла нет ни в бэкапах, ни в стандартном наборе Битрикс. Пришлось собирать его из архива версии 3.0.2 (2020 год) — там он лежит в шаблоне concept_kraken внутри wizard-установки, по пути install/wizards/concept/kraken/site/templates/concept_kraken/styles_and_scripts.php.
И тут снова PHP 8.1. В старом файле нашлось три проблемы:
- подключение
jquery-1.12.3.min.js— такого файла на сервере нет, замена наjqueryConcept.min.js, который реально лежит в папке шаблона; - подключение несуществующего
size-resize.js— просто убрать, иначе 404 на каждый хит; - синтаксис
{0}для индекса строки — фигурные скобки для смещений строк в PHP убрали ещё в 8.0, на 8.1 такой код падал ошибкой. Замена на классические[0].
# было (PHP 7)
$str{0} = strtoupper($str{0});
# стало (PHP 8.1)
$str[0] = strtoupper($str[0]);
Проверка результата
После заливки двух файлов сайт поднялся. Проверяю не только главную, а всё, что можно открыть без логина:
for url in / /about/ /contact/ /uslugi/ /tekushchie-raboty/ /vypolnennye-raboty/; do
code=$(curl -s -o /dev/null -w "%{http_code}" "https://example.ru$url")
echo "$url -> $code"
done
# / -> 200, /about/ -> 200, /contact/ -> 200, /uslugi/ -> 200 — все 200
1) Все разделы отвечают 200, /main/ отдаёт 301 на главную. 2) Админка открывается, модули видны в списке. 3) Минифицированные css/js отдаются 200 (в Кракене ассеты минифицируются модулем — если падает 500, значит класс снова не загрузился). 4) В HTML нет PHP-варнингов вроде «Undefined variable». 5) Композитный кэш активен, страницы открываются из кэша. 6) Посмотреть error_log за последние сутки — не растёт ли.
После восстановления не ограничиваюсь проверкой страниц — прохожу по типичным местам заражения: поиск eval(base64_decode и assert( по всем PHP-файлам, preg_replace с модификатором /e, новые администраторы в b_user, агенты и cron на посторонние команды, права файлов, неизвестные PHP-файлы в uploads. Здесь ничего не нашлось — сайт вернулся чистым.
Шаг 7. Обновить ядро и модули: без этого риск повторного взлома высок
Восстановить файлы — полдела. Сайт оставался на ядре 23.300.100 и модуле «Сайты 24» (landing) 23.600.150, и наиболее вероятной точкой входа оказался модуль landing. По данным техподдержки хостинга, безопасная версия начинается с 23.850.0. Пока ядро и модули не обновлены, риск повторного взлома остаётся очень высоким. Так и случилось на этом же сайте: в феврале 2026-го через ту же дыру залили новые лоадеры, хостинг чистил сайт, но модуль так и не обновили — и он продолжил работать из кэша до августа, пока кэш не очистили или не пересобрали.
Второй раз в сайт зашли через ту же дыру: эндпоинт
/bitrix/tools/landing/ajax.php позволял загрузить файл без авторизации. Хостинг в феврале временно блокировал этот адрес правилом в .htaccess, но файл .htaccess удалили, а модуль так и не обновили. Нашли 23+ лоадера и 6 cookie-шеллов — скрипты, которые активируются только при особом заголовке cookie и невидимы при обычном обходе.Порядок действий после восстановления файлов:
- Обновить ядро. Настройки → Обновление платформы → установить все доступные обновления. Было установлено 322 обновления (257 + 65): ядро 23.300.100 → 26.650.0.
- Обновить модули. Особенно landing: 23.600.150 → 26.600.0. Известная уязвимость закрывается обновлением.
- Заблокировать уязвимый эндпоинт в
bitrix/.htaccess— даже после обновления правило не мешает:
RewriteRule ^tools/landing/ajax\.php$ - [F,L,NC]
curl -s -o /dev/null -w "%{http_code}" "https://example.ru/bitrix/tools/landing/ajax.php"
# 403 — эндпоинт мёртв, файлы не зальются
Шаг 8. PHP 8.1 → 8.4: старый синтаксис и пересборка
Параллельно хостинг обновил PHP с 8.1.29 до 8.4.3. Здесь вылез старый код: строковые смещения {0} удалили из PHP ещё в 8.0, и на 8.4 все места, где они использовались, падали с ParseError. В модуле «Концепт. Кракен» и шаблонах нашлось 35 таких мест — CKraken.php (строки 31, 3264, 7173), result_modifier, template и lessc.inc.php:
# было
$value{0}
# стало
$value[0]
# каждый файл проверяем перед заливкой
php -l CKraken.php
# no syntax errors detected
Нюанс: файл CKraken.php к этому моменту был модифицирован злоумышленником (03.08, 18:22) — перед правками его сверяли с чистой копией из резервного архива. Правило для таких случаев: любые правки только после сверки с бэкапом, иначе можно «починить» чужой шелл.
После обновлений полностью сбросили кэш Битрикс: файловый (cache, managed_cache, stack_cache, html_pages) и таблицы БД (b_cache_tag, b_iblock_cache и др.). Сайт пересобрался с нуля на PHP 8.4. Права файлов: 63 257 файлов с 777 привели к 644/755. И повесили watcher — скрипт раз в минуту проверяет появление новых PHP-файлов и пишет в журнал:
# cron: */1 * * * * /home/user/watch.sh
# журнал: /home/user/watch.log
1) 322 обновления установлены без ошибок. 2) Уязвимый эндпоинт отдаёт 403. 3) php -l по всем файлам модуля без ошибок. 4) Сайт пересобран на PHP 8.4.3, страницы отдают 200. 5) Watcher не обнаруживает появления новых файлов.
Когда такой способ не сработает
Метод «вернуть файлы и подпатчить» работает не всегда. Реальные ограничения:
- Лицензия мертва — сайт работает, но обновления модуля и ядра Битрикс недоступны. Продление за 1800 ₽ ситуацию не спасает: маркетплейс не отдаёт архив модуля, а обновление установленного требует тарифа за 18 000 ₽. Это не «не сработает», а «работает с миной под собой»: уязвимости не закрываются, и следующая атака может быть страшнее — восстановить файлы снова будет неоткуда.
- Удалено больше трёх файлов — если взломщик вынес всю папку модуля или шаблона, патчить придётся десятки файлов. Тогда быстрее поставить шаблон заново из дистрибутива.
- Бэкап заражён — если взломщик оставил шелл внутри бэкапа, откат вернёт сайт вместе с дырой. Перед откатом всегда проверять uploads и загрузочные файлы.
- Магазинные функции — если модуль с корзиной, заказами, SKU, после такого патча нужно тестировать именно их: старый класс мог отличаться по API. У нас магазин на сайте вторичен, но корзину и заказ в админке я бы прогнал отдельно.
FAQ
Сайт упал или взломан — помогу поднять и закрыть дыры
Восстановление после взлома, чистка от малвари, бэкапы и защита. Напишите — разберу ваш случай за час.