Как найти точку взлома по логам хостинга
Разбор access.log и error.log после заражения: какие запросы выдают загрузку шелла, как сопоставить время правки файлов и очистить вход.
Содержание
- Зачем искать вход, если сайт уже почищен
- Где лежат логи и сколько они хранятся
- Шаг первый: находим свежеизменённые файлы
- Читаем access.log вокруг найденного времени
- Сигнатуры, которые почти всегда означают загрузку шелла
- Три сценария, которые встречаются чаще всего
- Что делать с найденным следом
- Когда искать точку входа лучше не самому
- Частые вопросы
Точку входа ищут так: находят самые свежие изменённые файлы, берут время их появления и читают лог доступа вокруг этой отметки. Логи у большинства хостингов живут от 7 до 30 дней, поэтому разбор откладывать нельзя: через месяц следа уже не будет.
Сайт почистили от шелла, обновили админский пароль, снесли подозрительные файлы, а через неделю или две зверинец возвращается: снова левый .php в uploads, снова редирект на казино или фарму при заходе с телефона. Знакомая история: чистка убирает симптом, а не причину, то есть точку входа, через которую злоумышленник попал внутрь. Эта статья про то, как найти эту точку по access.log и error.log хостинга: какие запросы в логах выдают загрузку шелла, как сопоставить время изменения файлов с записями в логах и что делать с найденным следом, чтобы не встретиться с той же историей ещё раз.

У меня в работе таких разборов за шесть лет практики было за полсотни. Схема почти всегда одна: клиент присылает «опять взломали», я прошу доступ по SSH или в панель хостинга, и первым делом иду не в файлы сайта, а в логи. Файлы расскажут, что случилось. Логи расскажут, как это случилось и через что.
Зачем искать вход, если сайт уже почищен
Чистка без поиска входа это как поменять разбитое стекло, но не заделать дыру в заборе, через которую туда лезут. Шелл удалили, а уязвимость, через которую его закинули, осталась: старая версия плагина, украденный пароль, забытый тестовый файл с правом на запись. Через какое-то время, иногда через день, иногда через месяц, тот же путь используется снова, потому что боты сканируют интернет непрерывно и хранят у себя список дырявых адресов.
Есть и вторая причина держаться логов, а не гадать. Если предстоит уведомлять хостинг о взломе, разбираться со страховкой или объяснять клиенту масштаб произошедшего (утекли ли пароли из базы, читал ли кто-то wp-config.php с доступами к базе), без логов это гадание на кофейной гуще. С логами это конкретный ответ: вот запрос, вот IP, вот что отправили на сервер и что сервер вернул в ответ.
Если пока непонятно, взломан сайт вообще или это баг после обновления плагина, начните с материала про признаки взлома сайта: там разбор симптомов, после которого вопрос «точно ли это взлом» обычно закрывается за пять минут.
Где лежат логи и сколько они хранятся
Логи веб-сервера, это первое, что нужно найти на хостинге. Раскладка путей и сроков хранения зависит от панели управления, но принцип одинаковый: каждый HTTP-запрос к сайту фиксируется одной строкой в access.log, а ошибки сервера, включая PHP fatal error, в error.log.
| Панель или хостинг | Где искать логи | Обычный срок хранения |
|---|---|---|
| cPanel | Раздел «Метрики» -> «Необработанный доступ» | 24-48 часов, старые архивы лежат в /home/user/logs/ |
| ISPmanager | Инструменты -> Логи, либо путь /var/www/user/data/logs/ | 7-30 дней в зависимости от настройки хостера |
| Timeweb | Личный кабинет -> сайт -> Логи, либо через SSH ~/logs/ | около 30 дней |
| Beget | SSH: ~/logs/domain.ru/ | около 90 дней |
| reg.ru shared | SSH: /home/uXXXX/logs/, либо раздел «Статистика» | около 30 дней |
Если готовой панели нет и доступ только через SSH, ищите логи так:
find / -iname "*access*log*" -newer /etc/hostname 2>/dev/null
find / -iname "*error*log*" -newer /etc/hostname 2>/dev/null
Учитывайте: если логи хранятся всего сутки-двое, а взлом обнаружили через неделю после факта, самих логов инцидента может уже не быть, ротация их стёрла. Это отдельный довод настроить выгрузку логов во внешнее хранилище заранее, а не после первого пожара.
Шаг первый: находим свежеизменённые файлы
Прежде чем читать мегабайты access.log, сузьте окно поиска. Найдите файлы, которые менялись позже всего: обычно это и есть шелл, бэкдор или изменённый файл темы либо плагина.
find /home/user/public_html -type f -mtime -7 -printf "%T@ %pn" | sort -n
Команда выведет все файлы, изменённые за последние 7 дней, отсортированные по времени правки. Файлы в конце списка (самые свежие) обычно и есть точка интереса. Если находите php-файл с именем вроде wp-loader.php, class-cache.php или .wp-tmp.php внутри папки uploads, это почти всегда шелл: исполнение PHP в uploads в норме вообще не нужно.
Время изменения этого файла (%T@ в выводе, unix timestamp) и есть та метка, вокруг которой дальше идёт поиск в access.log. Переведите её в читаемый формат:
date -d @1234567890
Дальше вся работа с логами строится вокруг этого времени, обычно с окном минус 10 минут (момент разведки и заброса файла) и плюс несколько минут после (первое обращение к самому шеллу, проверка, что он работает).
Читаем access.log вокруг найденного времени
Формат access.log обычно Common Log Format или Combined: IP, дата и время, метод и путь запроса, код ответа, размер тела, referer, user-agent. Пример строки за строкой:
185.220.101.7 - - [28/Jul/2026:03:14:22 +0300] "POST /wp-content/plugins/old-slider/upload.php HTTP/1.1" 200 512 "-" "python-requests/2.31"
185.220.101.7 - - [28/Jul/2026:03:14:41 +0300] "GET /wp-content/uploads/2026/07/wp-loader.php?cmd=whoami HTTP/1.1" 200 118 "-" "python-requests/2.31"
Вся история в двух строках: POST на уязвимый обработчик загрузки в старом плагине слайдера, через 19 секунд GET к свежесозданному шеллу с параметром cmd. User-agent python-requests, а не браузер, это тоже маркер: живой человек через форму сайта так не заходит.
Возьмите время, найденное на предыдущем шаге, и вытащите окружение:
grep "28/Jul/2026:03:1[0-5]" /home/user/logs/access.log
Ищите: POST-запросы (загрузка чаще всего идёт именно через POST), обращения к путям с plugins или uploads в адресе, один и тот же IP, повторяющийся несколько раз подряд с интервалом в секунды, нетипичный user-agent (пустой, curl, python-requests, скрипт вроде Go-http-client).
Сигнатуры, которые почти всегда означают загрузку шелла
Короткий чек-лист для быстрого прохода по логу, когда времени разбираться построчно нет:
- [ ] POST-запрос к файлу upload.php, import.php или ajax.php внутри папки старого либо неизвестного плагина
- [ ] GET-запрос к .php файлу внутри /wp-content/uploads/, где в норме исполняемого кода быть не должно
- [ ] Параметры вида ?cmd=, ?c=, ?0=, ?1= в запросе к подозрительному файлу, типичный интерфейс веб-шелла
- [ ] User-agent пустой либо явно не браузерный: curl, python-requests, Go-http-client, libwww-perl
- [ ] Один IP делает десятки запросов за секунды, методично перебирая пути (сканирование известных уязвимостей)
- [ ] Обращение к xmlrpc.php с большим телом POST-запроса (перебор паролей или эксплуатация через XML-RPC)
- [ ] Обращение к /wp-admin/admin-ajax.php с action, которого нет в списке легитимных плагинов сайта
Если совпало хотя бы три пункта, а время примерно совпадает с моментом появления нового файла, точка входа найдена.
Три сценария, которые встречаются чаще всего
Дыра в устаревшем плагине
Самый частый случай из тех, что я вижу. Плагин с известной уязвимостью, обычно из тех, что называют arbitrary file upload или SQL injection, не обновлялся месяцами, эксплойт публичный, боты сканируют интернет автоматически по базе таких дыр. В логе видно прямое обращение к уязвимому файлу плагина без всякой авторизации, часто в течение первых суток после публикации эксплойта. Лечится обновлением или удалением плагина, но сначала полной чисткой файлов сайта. О том, как именно чистить, подробно писал в статье как очистить WordPress от вирусов.
Украденный пароль от FTP или админки
В этом случае в access.log никакого эксплойта не видно вообще: заход в /wp-login.php с валидным логином и паролем, дальше легитимная загрузка плагина или темы через админку, внутри которой уже зашит шелл. Ищите такие входы по IP, который не совпадает с обычной географией владельца сайта, и по времени, нетипичному для рабочего графика клиента (глубокая ночь по Москве, например). Если пароль в принципе был слабым или использовался ещё где-то, вопрос закрыт: он утёк, и дальше стоит прочитать про безопасные пароли для админки.
Сосед по общему хостинг-аккаунту
Встречается реже, но встречается: на shared-хостинге с несколькими сайтами в одном аккаунте заражён один из сайтов-соседей, а через общие права на файлы или через общий tmp-каталог шелл переползает на все сайты аккаунта разом. В access.log вашего сайта в этом случае может не быть ничего подозрительного вовсе, потому что вход был не через ваш сайт. Проверяется просто: смотрите даты создания подозрительных файлов на всех сайтах аккаунта, если совпадают день в день или час в час, дело именно в этом.
Что делать с найденным следом
- Закрыть конкретную дыру: обновить или удалить уязвимый плагин, сменить пароль, если он утёк, поправить права на файлы, если проблема оказалась в соседях по аккаунту.
- Сменить все пароли, которые могли быть доступны через сайт: админка CMS, FTP или SSH, база данных, почта на том же хостинге.
- Перевыпустить ключи и соли в wp-config.php (или аналогичном файле для другой CMS), это обесценивает украденные куки авторизации, если они успели утечь.
- Проверить остальные сайты в том же хостинг-аккаунте, если они есть, той же методикой поиска свежих файлов.
- Настроить бэкапы вне хостинга, если их не было. Подробности в статье про резервные копии на хостинге или в облаке: следующее восстановление не должно зависеть от того же взломанного окружения.
- Через неделю повторить поиск свежих файлов той же командой find, чтобы убедиться, что это тишина, а не пауза перед новой волной.
Когда искать точку входа лучше не самому
Разбор логов это час-два методичной, но не сложной работы, если знаешь, что искать. Проблема в том, что искать приходится в состоянии стресса, когда сайт уже лежит или на нём висит предупреждение браузера, а времени разбираться по шагам нет. Если сайт на минимальном тарифе, логи хранятся сутки, а разбор нужен здесь и сейчас, возьмите это как отдельную задачу: такой разбор я делаю в рамках разовой чистки или абонентского обслуживания, с итоговым отчётом о том, что нашли и что закрыли. Если заражение активное прямо сейчас, пишите через форму на сайте, в таких случаях важна скорость реакции, а не переписка на следующий день.
Частые вопросы
Зачем искать точку входа, если сайт уже почистили
Потому что чистка убирает симптом. Пока дыра открыта, шелл возвращается через неделю-другую, и так по кругу. Повторное заражение после чистки почти всегда означает, что вход не нашли.
Где лежат логи и сколько хранятся
В панели хостинга в разделе со статистикой или логами, либо в домашней директории по SSH. Срок хранения от 7 до 30 дней у большинства площадок, у части до 90.
Как найти нужное место в логе
Сначала найти самые свежие изменённые файлы и запомнить время. Потом смотреть запросы за эти минуты: там будет POST на непонятный адрес или обращение к скрипту, которого в сайте нет.
Через что заходят чаще всего
Через устаревший плагин или модуль с публично известной уязвимостью. Реже через подобранный пароль и украденные доступы FTP. Самописный код тоже даёт свою долю, но заметно меньшую.