ПІДТРИМКА САЙТІВ · РЕАЛЬНИЙ КЕЙС
Сайт на WordPress зламали. Ось що я виявив.
Реальне очищення WordPress: як ручний моніторинг став початком перевірки, що підтвердили завершені тести та чому останню заявку простежили до отримувача.

Сайт на WordPress може відкриватися як завжди й водночас передавати відвідувачам код, якого власник не додавав. У цьому випадку прихований плагін вставляв сторонній скрипт у публічні сторінки, в різних частинах сайту були несанкціоновані файли, а сканер безпеки завершувався помилкою ще до початку перевірки.
Аномалію я першим помітив під час ручного моніторингу сайту клієнта й почав глибшу перевірку. Клієнт не зазнав фінансових втрат через цей інцидент. Звіт Google Analytics про незвичну активність надійшов приблизно через добу після того, як я вніс виправлення.
Я поєдную автоматичні перевірки з особистим переглядом сайтів своїх клієнтів. У цьому випадку я помітив підозрілу активність раніше, ніж на неї звернули мою увагу автоматичні інструменти або AI-помічник із доступом до сайту. Саме це спостереження стало початком описаної нижче перевірки.
Під час робіт, задокументованих 15–16 вересня, я ізолював джерело ін’єкції, перемістив у карантин 37 окремих файлів, відновив компоненти з перевірених пакетів там, де вони були доступні, та відновив роботу сканера. Також я надіслав тестову заявку й отримав від власника підтвердження, що вона надійшла.
Для власника бізнесу практичне питання звучить так: які докази дають підстави знову покладатися на сайт? У цьому випадку знадобилися перевірка відповідей публічних сторінок, порівняння файлів із перевіреними оригіналами, завершені сканування та тестування шляху заявки. Кожна перевірка відповідала на окрему частину цього питання.
Цей випадок також показує, чому вибір перевіреного розробника й постійну технічну підтримку варто закладати в бюджет сайту від самого початку. Якщо кваліфікований фахівець не стежить за сайтом і не розбирається зі сповіщеннями, злам може залишитися непоміченим. Залежно від дій зловмисника наслідками можуть стати втрачені заявки, змарновані витрати на рекламу, оплата відновлення та втрата довіри клієнтів.
Ім’я клієнта та дані, за якими можна ідентифікувати його інфраструктуру, не розкриваються. Наведені результати відповідають доказам, доступним на момент завершення описаних робіт.
Пошукові дані допомогли дослідити помічену аномалію
Сторонній спамний запит отримав 4 979 показів і два кліки у тримісячному звіті Google Search Console, який я переглянув. Покази були зосереджені у двох послідовних днях наприкінці серпня. За перевірені вересневі дати показів саме цього запиту не було.
Це дало конкретний напрям для перевірки. Але не встановило, коли почався чи закінчився злам.
Я перевірив вибрані спамні слова в експортованому вмісті 232 дописів і 34 сторінок, а також у 873 URL із п’яти файлів карти сайту. Цих слів я там не знайшов. Водночас однаковий несанкціонований зовнішній скрипт був у HTML-відповідях восьми перевірених публічних сторінок.
WordPress додавав код під час формування відповіді. Пошук у збереженому тексті сторінок не міг показати все, що отримували відвідувачі.
Документація Google описує ін’єкції коду як у HTML, так і у файли, що формують сторінки. Вона також пояснює, що шкідлива поведінка може залежати від обставин відвідування. Тому разом зі збереженим вмістом і пошуковими звітами варто перевіряти те, що сайт фактично віддає користувачам. Google Search Console: Security Issues
У цьому випадку я підтвердив активне додавання стороннього коду. Зв’язок із конкретним падінням позицій залишився недоведеним.
Плагін приховував себе в панелі керування
Компонент мав назву Site Assets, яка могла здатися звичайною службовою утилітою для сайту.
Його код приховував плагін зі стандартного списку, пригнічував інформацію про оновлення та вставляв зовнішній скрипт у вміст сторінок. Я зіставив механізм ін’єкції всередині активного плагіна з тегом скрипту в публічних відповідях.
Під час перевірки зламаного WordPress це важлива обставина: список плагінів у панелі керування може бути неповним. Потрібно порівнювати дані інтерфейсу з файлами на диску та збереженою конфігурацією сайту.
Я навмисно не запускав віддалений скрипт. Його повна поведінка, зокрема вплив на окремих відвідувачів, залишилася за межами встановлених фактів.
WordPress скасував першу спробу зупинити ін’єкцію
Спочатку я спробував через редактор плагінів WordPress зупинити виконання підтвердженого шкідливого компонента, зберігши його код. WordPress не зміг виконати зворотний запит до сайту для перевірки критичних помилок, відхилив редагування та скасував зміну.
Я знову отримав відповідь головної сторінки. Скрипт залишався на місці.
Далі робота перейшла на рівень сервера. Я зберіг плагін і перемістив його за межі публічного каталогу сайту. У нових відповідях чотирьох перевірених сторінок відомого скрипту вже не було.
Саме зовнішня перевірка підтвердила, що ін’єкцію вдалося зупинити. До цього дія в редакторі залишалася лише спробою змінити сайт.
Подальша перевірка виявила файли за межами видимої ін’єкції
Видалення завантажувача зупинило появу спостережуваного скрипту. Але ще потрібно було перевірити способи, якими зловмисник міг зберегти доступ.
Я знайшов несанкціоновані або підозрілі файли в кореневому каталозі сайту, каталогах ядра, завантаженнях та неактивних темах. Деякі містили PHP-код під розширеннями зображень або архівів. В одному плагіні з офіційного репозиторію було змінено головний файл і додано файли, відсутні в офіційному пакеті. Інші фрагменти коду містили функції прихованого доступу або керування файлами.
На задокументованих етапах карантину я перемістив з робочого сайту 37 окремих файлів, додатково до прихованого плагіна та збережених копій компонентів. Це кількість опрацьованих файлів, а не окремих атак.
Я зберіг оригінали разом із записами шляхів, розмірів, часу зміни та хешів. Перед масштабним відновленням я також експортував базу даних і створив архів файлів сайту.
Ця робота мала обмеження: архів я створював з активного сайту вже після первинної ізоляції, і частину файлів я переміщував в карантин, поки архівування ще тривало. Їхні оригінали я зберіг окремо. Архів був корисним для відновлення та дослідження, але не був узгодженим знімком усього середовища в один момент часу.
У подібному випадку варто якомога раніше зробити узгоджений знімок і захистити копію доказових матеріалів поза сервером. Архів зі зламаного сайту також потрібно перевірити, перш ніж використовувати його як безпечне джерело відновлення.
Перевірені оригінали визначали, що я міг підтвердити
Я зберіг змінений плагін із репозиторію та відновив його з офіційного пакета. Коли наступне сканування позначило його як такий, що більше не підтримується, власник видалив його. Три неактивні стандартні теми WordPress я відновив з офіційних архівів, а потім оновив.
Ядро WordPress пройшло перевірку за офіційними контрольними сумами. Після обслуговування усі 15 плагінів із репозиторію, що залишилися, пройшли сувору перевірку за офіційними контрольними сумами.
Порівняння контрольних сум показує, чи відповідають файли еталону. WP-CLI має окремі перевірки для ядра WordPress і плагінів із репозиторію. Кожна має визначені межі: успішна перевірка плагіна не перевіряє базу даних, комерційну тему або операційну систему.
Комерційна тема показала, чому важливе походження еталона. Із 1 112 установлених файлів 1 111 збігалися із завантаженим власником пакетом із маркетплейсу. Решта — один файл — містила відповідний оригінал із доданим фільтром спаму для контактної форми. Я перевірив цей додаток.
Однак у самому завантаженому пакеті вже була модифікація статусу ліцензії. Він підтверджував відповідність придбаному ZIP-архіву, але не міг бути незалежним еталоном чистого релізу розробника. Я не встановив, що причиною зламу стала тема або її продавець.
Збережений доступ до офіційних інсталяційних пакетів спрощує цю частину відновлення. Порівняння також має враховувати зайві файли, які можуть залишитися після перезапису каталогу.
Спочатку потрібно було відновити роботу сканера
На одному з етапів Wordfence показував збій сканування, нуль перевірених об’єктів і нуль знахідок. Нуль знахідок у цьому випадку означав, що сканер не виконав роботу.
Діагностика показала: запит до власного домену сайту отримував відповідь HTTP 403 та інтерактивну перевірку Cloudflare. Фоновий запит не міг її пройти.
Вузько налаштований виняток пропустив діагностичний POST-запит, і перевірка з’єднання завершилася успішно. Саме сканування все ще не запускалося належним чином.
Я перевірив встановлений офіційний код Wordfence. У цій версії тест з’єднання використовував POST, а запуск сканування — GET із параметрами сканування. Діагностика та реальна операція виконували різні запити.
За згодою власника я уточнив правило для перевіреного джерела запиту — сервера, конкретного хоста, кінцевої точки та потрібних умов. Wordfence і далі мав сам перевіряти автентичність запиту на сканування. Після цього я побачив рух лічильників, нові записи журналу та запис про завершення.
Документація Wordfence називає блокування серверних з’єднань і обмеження доступу до AJAX-обробника WordPress серед можливих причин збоїв сканування. Конкретну відмінність POST/GET я встановив під час перевірки встановленої версії. Wordfence: Scan Troubleshooting
Завершені перевірки мали конкретні межі
Перше завершене сканування Wordfence охопило 86 239 файлів і тривало 49 хвилин 30 секунд. На момент перегляду в поточному списку результатів не було знахідок шкідливого коду. Залишалися чотири попередження щодо обслуговування: плагін без підтримки та три оновлення тем. Проігнорованих знахідок не було.
Власник видалив плагін, а теми я оновив. Після цих змін я запустив ще одне сканування, але на момент завершення запису кейсу воно ще тривало. Його проміжні результати тут не подаються як завершена перевірка.
Сканер використовував набір сигнатур Community; в інтерфейсі було зазначено затримку на 30 днів. Тому я розглядав його результати разом із ручною перевіркою та перевірками цілісності файлів.
| Доказ | Що він підтвердив |
|---|---|
| У чотирьох нових відповідях публічних сторінок не було відомого скрипту | Після карантину спостережуваний індикатор був відсутній у цих зразках |
| Ядро та 15 плагінів із репозиторію пройшли перевірку контрольних сум | Охоплені перевіркою файли відповідали офіційним еталонам |
| Статична перевірка охопила 13 634 відібрані файли | Вибрані перевірки завершилися без помилок читання; обмеження за сигнатурами й розміром файлів залишалися чинними |
| Wordfence завершив сканування | Сканер виконав роботу; переглянутий список містив описані вище результати |
| Власник отримав тестову заявку | Перевірена форма та маршрут доставки працювали після змін |
Я також посилив два інфраструктурні обмеження: заблокував PHP-подібні запити в каталозі завантажень і обмежив старий прямий HTTP-доступ до панелі керування сервером. Зовнішні тести підтвердили блокування перевіреного маршруту завантажень і припинення відповідей через прямий IPv4-доступ до панелі, тоді як HTTPS залишався доступним. Збереження правил після перезавантаження та окрему зовнішню перевірку IPv6 я не підтверджував під час цієї сесії.
Остання бізнес-перевірка простежила заявку до отримувача
Після очищення та обслуговування я перевірив головну сторінку, сторінку послуги й контактну сторінку. Я надіслав одну погоджену тестову заявку з повідомленням «Test».
Форма показала повідомлення про успіх і очистила поля. Після цього власник підтвердив отримання.
Це були два окремі спостереження. Реакція форми підтвердила проходження відправлення через інтерфейс, а підтвердження власника — доставку перевіреної заявки до адресата.
Для бізнесу, який отримує звернення із сайту, така перевірка має входити до критеріїв приймання робіт. Різні форми та інтеграції потребують окремих тестів.
Професійна розробка та підтримка мають конкретний склад робіт
Цей сайт був професійно розроблений, із налаштованим хостингом і засобами захисту. На ньому вже були Cloudflare та плагін безпеки, а AI-помічник мав доступ. Інцидент усе ж стався. Аномалію виявив мій ручний моніторинг, а звіт Google Analytics надійшов приблизно через добу після виправлень.
Для мене це причина відповідально ставитися до всього, що забезпечує роботу сайту. Захисні заходи зменшують ризик, а постійний нагляд закріплює за конкретною людиною обов’язок помітити незвичну поведінку, розібратися та відреагувати. Підготовка також дає бізнесу шлях до відновлення.
Коли бізнес порівнює пропозицію сайту за $1 000 або дешевше з комплекснішим проєктом, я пропоную порівняти конкретні роботи й подальшу відповідальність:
- Розробка: дизайн, реалізація, зручність на мобільних пристроях, перевірка форм та інтеграцій.
- Хостинг і налаштування: відповідне серверне середовище, контроль доступу та чітко визначена відповідальність за адміністрування.
- Захист і відновлення: перевірені джерела програмного забезпечення, налаштування безпеки, захищені резервні копії та порядок перевірки відновлення.
- Постійна підтримка: оновлення, моніторинг, розбір сповіщень, тести після змін і погоджений порядок реагування.
Для цього потрібні час, знання та подальша робота. Попросіть виконавця окремо вказати вартість розробки, хостингу, ліцензій і регулярної підтримки. Сама ціна мало говорить про те, що включено та хто відповідає за сайт після запуску.
Саме тому я розглядаю професійну розробку сайту як інвестицію з визначеним обсягом робіт. Перш ніж обрати пропозицію, з’ясуйте, що ви отримуєте, що залишається вашою відповідальністю та що відбуватиметься в разі зламу.
У цьому кейсі навіть сканер потребував перевірки, перш ніж зміг завершити роботу. AI та інструменти безпеки допомагають, але не замінюють професійної оцінки, потрібної, щоб розпізнати проблему, визначити напрям дослідження й підтвердити результат.
Документація WordPress щодо безпеки охоплює перевірені джерела програмного забезпечення, оновлення, резервні копії та моніторинг. Це постійні заходи зі зменшення ризику; відповідальність за хостинг і сам сайт потрібно чітко розподілити. WordPress: Hardening
Клієнт не зазнав фінансових втрат через цей інцидент. Для бізнесу, де злам залишається непоміченим, можливі наслідки — втрачені заявки, змарновані витрати на рекламу, оплата відновлення та втрата довіри клієнтів. Професійна підготовка й активна підтримка покликані зменшувати ці ризики та покращувати можливості виявлення проблем і відновлення.
Коли потрібне ширше розслідування
Цей кейс описує очищення сайту та вибрані інфраструктурні перевірки. Якщо є підозра на доступ до даних клієнтів, повторне зараження або неможливо встановити цілісність середовища, потрібне ширше розслідування інциденту. Відновлення може вимагати перебудови середовища з перевірених джерел.
У цьому випадку початкова точка проникнення, повна поведінка віддаленого скрипту та можливий доступ до приватних даних залишилися невстановленими. Запис також не підтверджував завершення заміни всіх облікових даних доступу чи повного експертного дослідження сервера.
Ці відкриті питання визначають подальшу роботу. Їх варто залишати видимими у звіті навіть після видалення виявленої ін’єкції та успішної перевірки форми.
Що власнику бізнесу варто отримати у звіті
Корисний звіт про очищення має давати відповіді на п’ять питань:
- Який несанкціонований код або поведінку виявили й де саме?
- Що ізолювали або відновили та які оригінали зберегли?
- Які перевірки завершили й що вони охопили?
- Чи пройшла тестова заявка або покупка весь шлях до свого адресата?
- Що залишилося невирішеним і хто відповідає за подальші дії?
У цьому випадку задокументованим результатом стали видалення встановленого джерела ін’єкції, карантин зафіксованих файлів, перевірене відновлення за доступними офіційними еталонами, робочий сканер і підтверджена доставка тестової заявки.
Для локального бізнесу підтримка сайту й маркетинг сходяться на цьому останньому кроці: сайт має доставити звернення відвідувача до компанії.
Плануєте роботу над сайтом, Local SEO або видимістю в AI? Завітайте на Koliesnikov.com, щоб обговорити сайт і цілі вашого бізнесу. Якщо ви розбираєтеся з незвичною пошуковою активністю, підготуйте для першої розмови відповідні URL, дати та приклади.
Про автора: Oleksandr Koliesnikov — фахівець із Торонто з AI Visibility, GEO, Local SEO та цифрового маркетингу, який особисто працює над проєктами локального бізнесу в Канаді та США.

