Wirus na WordPress wraca po usunięciu? Case study

Okno terminala z logiem serwera: dwa żądania POST na endpoint wtyczki i po nich webshell

Hosting napisał, że wirusy zostały usunięte. Strona działa, sklep przyjmuje zamówienia, w panelu nic nie miga na czerwono. Trzy dni później w Google pojawiają się adresy Twojej domeny, których nigdy nie utworzyłeś. Jeśli wirus na WordPress wraca po usunięciu, to zwykle nie znaczy, że czyszczenie zrobiono niestarannie. Znaczy, że usunięto skutek, a nie drogę wejścia. We wrześniu 2026 czyściliśmy stronę klienta cztery razy w ciągu doby, zanim znaleźliśmy prawdziwą przyczynę. Był nią komponent, który przeszedł każdą kontrolę, bo był w pełni legalny.

Artykuł w skrócie

  • Reinfekcja WordPressa oznacza otwarty wektor wejścia. Skan antywirusowy hostingu wykrywa pliki po sygnaturach, nie wykrywa luk w kodzie ani kont założonych przez atakującego.
  • W opisywanym przypadku drogą wejścia była płatna wtyczka WPMU DEV Dashboard z lukami CVE-2026-15459, CVE-2026-16051 i CVE-2026-76581. Atakujący wchodził przez nią siedem razy w ciągu ośmiu dni, bez hasła i bez konta.
  • Skutkiem był SEO spam: ponad milion podstawionych adresów w indeksie Google, widocznych wyłącznie dla Googlebota.
  • Wtyczki spoza oficjalnego repozytorium WordPressa nie pojawiają się na liście dostępnych aktualizacji. Rutynowa aktualizacja wszystkich wtyczek ich nie obejmuje.
  • Odwirusowanie z ustaleniem wektora zajmuje od 2 do 8 godzin, co przy stawce 200 zł netto za godzinę daje od 400 do 1600 zł netto.
  • Dwa polecenia na końcu artykułu pozwolą Ci sprawdzić własną stronę w minutę.

Dlaczego wirus na WordPress wraca po usunięciu

To jest sedno całego artykułu, więc powiemy to wprost: usunięcie złośliwych plików nie jest usunięciem infekcji. Pliki są skutkiem. Przyczyną jest droga, którą atakujący wszedł, i jeśli ta droga nadal jest otwarta, wróci tą samą trasą w ciągu godzin.

Typowe czyszczenie, które nie działa, wygląda tak:

  1. Hosting uruchamia skan antywirusowy i kasuje wykryte pliki.
  2. Ktoś reinstaluje WordPressa z oficjalnej paczki.
  3. Ktoś zmienia hasła do FTP i do panelu.
  4. Strona przez chwilę jest czysta.
  5. Infekcja wraca.

Każdy z tych kroków jest sam w sobie sensowny. Problem polega na tym, że żaden nie odpowiada na pytanie którędy. Skaner antywirusowy porównuje pliki z bazą sygnatur. Nie sprawdza, czy któraś z wtyczek ma lukę, przez którą można wgrać nowy plik pięć minut po skasowaniu starego.

W naszym przypadku było jeszcze gorzej, bo pierwsze czyszczenie pominęło trzy rzeczy, które decydują o wszystkim:

  • Konto administratora założone przez atakującego. Usunięto pliki, zostawiono konto. Atakujący po prostu zalogował się ponownie.
  • Aktywne sesje. Zmiana hasła nie wylogowuje nikogo, kto jest już zalogowany. Trzeba unieważnić sesje i wymienić klucze szyfrujące, inaczej ciasteczko atakującego działa dalej.
  • Wektor wejścia. O tym za chwilę, bo to najciekawsza część historii.

Jak rozpoznać SEO spam, czyli infekcję widoczną tylko dla Google

Najczęstszy scenariusz nie polega na tym, że strona przestaje działać. Wręcz przeciwnie: dla Ciebie i dla Twoich klientów wszystko wygląda w porządku. Problem widzi tylko Google.

Mechanizm nazywa się cloakingiem. Złośliwy skrypt sprawdza, kto puka do drzwi. Jeśli to zwykła przeglądarka, dostaje prawdziwą stronę. Jeśli to robot wyszukiwarki, dostaje wygenerowany katalog podróbek, leków bez recepty albo kasyn online. W przypadku naszego klienta w ciągu siedmiu dni Googlebot pobrał 1 012 153 takich adresów pod domeną firmy.

Objawy, które powinny Cię zaniepokoić:

  • W Google Search Console rośnie liczba zaindeksowanych stron, których nie tworzyłeś. Pojawiają się dziwne podstrony, zwykle w schemacie /items/, /good/shop/, /shop/pg/ z losowymi symbolami.
  • Wyszukiwanie site:twojadomena.pl pokazuje adresy w rodzaju /items/, /good/shop/, /shop/pg/ z losowymi symbolami.
  • Search Console zgłasza problemy dotyczące bezpieczeństwa albo Google wyświetla ostrzeżenie przed wejściem na stronę.
  • Ruch organiczny spada, mimo że nic nie zmieniałeś w treści.
  • Hosting przysyła informację o wykryciu złośliwych plików.
  • Poczta z Twojej domeny zaczyna trafiać do spamu, bo serwer rozsyła wiadomości bez Twojej wiedzy.
  • W wynikach wyszukiwania pod Twoją domeną widać chińskie albo japońskie znaki.

Warto od razu odróżnić dwie sytuacje. Infekcja widoczna dla użytkownika, czyli przekierowania na obce strony albo wyskakujące reklamy, jest łatwiejsza do zauważenia i zwykle prostsza do usunięcia. Infekcja widoczna wyłącznie dla wyszukiwarki potrafi działać miesiącami, zanim ktokolwiek ją zauważy, i to ona wyrządza największe szkody w pozycjach.

Przebieg infekcji krok po kroku

Klient: sklep internetowy na WordPressie z WooCommerce, kilka lat współpracy, branża techniczna. Zgłoszenie przyszło z informacją od hostingu, że infekcja została usunięta.

Kiedy weszliśmy na serwer, infekcja była aktywna. Ostatnie pliki atakującego powstały trzy godziny wcześniej. Znaleźliśmy 27 złośliwych plików, fałszywą wtyczkę odtwarzającą tylne wejście przy każdym załadowaniu strony, konto administratora założone miesiąc wcześniej, dwanaście adresów IP korzystających z powłok webowych i plik konfiguracyjny serwera, który blokował wszystkie skrypty PHP poza białą listą backdoorów.

Wykonaliśmy pełne czyszczenie: kopia dowodowa, kwarantanna, rdzeń WordPressa z oficjalnej paczki, usunięcie obcego konta, unieważnienie sesji, wymiana kluczy, rotacja haseł, blokada adresów IP. Wieczorna kontrola: czysto. Kontrola następnego dnia wieczorem: backdoor z powrotem, z datą sprzed kilkudziesięciu sekund. Plik odtwarzał się w trakcie skanowania.

49 sekund, które wyjaśniły wszystko

Zamiast szukać kolejnych plików, zawęziliśmy logi serwera do minuty, w której powstał backdoor. Cała sekwencja trwała 49 sekund:

Godzina Żądanie Odpowiedź
07:25:00 GET / 200
07:25:07 POST /?wpmudev-hub=<podrobiony podpis> 200
07:25:30 POST /?wpmudev-hub=<podrobiony podpis> 200
07:25:39 GET /wp-content/plugins/background-image-cropper/accesson.php 200
07:25:46 POST /wp-content/plugins/background-image-cropper/accesson.php 200

Dwa żądania na adres wtyczki, a dziewięć sekund później działająca powłoka webowa. Bez logowania, bez hasła, bez wykorzystania jakiegokolwiek konta. Ten sam wzorzec znaleźliśmy w logach siedem razy w ciągu ośmiu dni, zawsze po czyszczeniu, z adresów w Estonii, Holandii i Zjednoczonych Emiratach.

Wektor wejścia: wtyczka WPMU DEV Dashboard i luki CVE-2026-15459, 16051 oraz 76581

WPMU DEV Dashboard to wtyczka do zdalnego zarządzania wieloma stronami WordPress z jednego panelu. Około 350 tysięcy instalacji na świecie. Robi dokładnie to, czego się od niej oczekuje: przyjmuje polecenia z zewnątrz i wykonuje je z uprawnieniami administratora. Instaluje wtyczki, zakłada konta, loguje bez hasła.

Zainstalowana u klienta wersja 5.0.0 była podatna na trzy luki:

Identyfikator Ocena Co daje atakującemu Poprawka
CVE-2026-15459 8,1 Podrobienie podpisu żądania na adresie ?wpmudev-hub= i instalacja dowolnej wtyczki, czyli wykonanie dowolnego kodu 5.0.1
CVE-2026-16051 9,8 Brak weryfikacji integralności instalowanych paczek i brak ochrony przed powtórzeniem podpisanego żądania 5.0.1
CVE-2026-76581 9,8 Sesja administratora przez niespójny podpis w mechanizmie logowania jednokrotnego 5.0.2

Wszystkie sprowadzają się do tego samego: podpis żądania dawało się podrobić, więc uwierzytelnienie było fikcją. Pierwsza z tych luk została opublikowana 6 sierpnia 2026. Tego samego dnia na stronie klienta powstało obce konto administratora. To nie zbieg okoliczności, tylko automat, który przeczesał internet w poszukiwaniu podatnych instalacji w dniu ujawnienia luki.

I teraz najważniejsze zdanie w całym artykule:

Ta wtyczka nie jest hostowana w oficjalnym repozytorium WordPressa. Jest płatna i aktualizuje się wyłącznie przez połączenie z panelem producenta. Nie pojawia się na liście dostępnych aktualizacji obok pozostałych wtyczek. Rutynowa aktualizacja wszystkich wtyczek, wykonana kilka dni wcześniej, objęła każdą inną i nie mogła objąć tej. Bezpieczna wersja 5.0.2 była dostępna od dwóch tygodni.

Powiemy uczciwie: my też nie wychwyciliśmy jej przy pierwszym czyszczeniu. Wtyczka przeszła weryfikację jako legalna, bo legalna była.

Atakujący usunął nam wtyczkę bezpieczeństwa

Osiem godzin przed kontrolą, która wykryła nawrót, atakujący odinstalował zainstalowany przez nas dzień wcześniej system zabezpieczeń. Nie obszedł go. Usunął, korzystając z tego samego kanału zdalnego zarządzania.

To ważna lekcja o granicach takich narzędzi. Wtyczka bezpieczeństwa działa wewnątrz aplikacji, którą ma chronić. Dopóki atakujący nie ma uprawnień administratora, jest skuteczna. Kiedy je ma, staje się kolejnym plikiem do skasowania.

Jak znaleźć backdoora w WordPress

Backdoor to plik albo fragment kodu pozwalający wrócić na serwer bez logowania. Najczęstsze kryjówki:

  • Katalog główny strony. Pliki o nazwach udających systemowe, na przykład accesson.php, albo losowy ciąg znaków w rodzaju 59bef8a914a1.php.
  • Fałszywa wtyczka. Katalog w wp-content/plugins/ noszący nazwę prawdziwej, porzuconej wtyczki. W naszym przypadku było to background-image-cropper, które samo w sobie ma lukę CVE-2024-58348.
  • Katalog mu-plugins. Wtyczki obowiązkowe ładują się zawsze i nie da się ich wyłączyć z panelu.
  • Katalog z plikami użytkowników. W wp-content/uploads/ nie powinno być ani jednego pliku PHP.
  • Baza danych. Zaplanowane zadania, wpisy w tabeli opcji, wtyczki wykonujące kod zapisany w bazie.
  • Pliki konfiguracyjne serwera. Wpisy w .htaccess przekierowujące ruch albo odblokowujące konkretne skrypty.

Sygnatury, których warto szukać w kodzie: eval(base64_decode(, gzinflate, gzuncompress oraz autoryzacja przez wartość ciasteczka. Część z nich występuje też w legalnym kodzie, więc każde trafienie trzeba zweryfikować sumą kontrolną pliku.

Najskuteczniejsza metoda nie polega jednak na szukaniu plików, tylko na czytaniu logów. Bierzesz datę utworzenia złośliwego pliku i sprawdzasz, jakie żądania trafiły na serwer w tej samej minucie. Odpowiedź prawie zawsze tam jest.

Milion spamowych adresów w Search Console. Jak je usunąć

Usunięcie infekcji nie usuwa jej skutków w wyszukiwarce. Podstawione adresy zostają w indeksie, a wraz z nimi ostrzeżenia i utracone pozycje. To osobna praca i większość poradników w ogóle o niej nie wspomina.

  1. Upewnij się, że spamowe adresy zwracają 404 albo 410. Kod 410 mówi wyszukiwarce, że zasób zniknął na stałe, i przyspiesza usuwanie z indeksu. Nie przekierowuj ich na stronę główną, bo to konserwuje problem.
  2. Sprawdź plik robots.txt. Malware często dopisuje do niego własną mapę witryny. Usuń obce wpisy.
  3. Skasuj podstawione mapy witryny i zgłoś prawidłową w Search Console.
  4. Nie blokuj spamowych adresów w robots.txt. To częsty błąd. Zablokowanego adresu robot nie może sprawdzić, więc zostaje on w indeksie na dłużej.
  5. Skorzystaj z narzędzia usuwania adresów URL w Search Console. Działa na prefiksy, więc jednym zgłoszeniem obejmiesz cały katalog ze spamem.
  6. Sprawdź listę zweryfikowanych właścicieli witryny. Atakujący potrafi się tam dopisać, żeby zachować wgląd po wyczyszczeniu strony. O tym zapomina się najczęściej.
  7. Zgłoś wniosek o ponowne rozpatrzenie, jeśli w sekcji problemów dotyczących bezpieczeństwa widniało ostrzeżenie. Opisz, co się stało i co zostało naprawione.

Realistycznie: usunięcie ostrzeżenia zajmuje zwykle kilka dni od zgłoszenia. Wyczyszczenie indeksu z dużej liczby adresów to tygodnie. Odbudowa pozycji zależy od tego, jak długo spam był indeksowany, i przy infekcji trwającej miesiąc bywa kwestią jednego lub dwóch kwartałów.

Dlaczego czyszczenie przez hosting ani przywrócenie kopii nie wystarczą

Zbierzmy w jednym miejscu działania, które ludzie podejmują w dobrej wierze, licząc, że wystarczą.

Działanie Dlaczego samo nie wystarczy
Skan antywirusowy hostingu Wykrywa pliki po sygnaturach. Nie wykrywa luk w kodzie ani kont założonych przez atakującego.
Reinstalacja WordPressa Podmienia rdzeń, nie dotyka wtyczek, bazy danych ani kont. Wektor zwykle siedzi we wtyczce.
Zmiana haseł Pomaga tylko wtedy, gdy atakujący wszedł przez hasło. W naszym przypadku nie potrzebował żadnego.
Przywrócenie kopii zapasowej Kopia sprzed infekcji zawiera tę samą podatną wtyczkę. Przywracasz stan, w którym włamanie jest znowu możliwe.
Instalacja wtyczki bezpieczeństwa Wartościowa jako monitoring, ale nie zamyka luki i można ją usunąć, mając uprawnienia administratora.

Zwróć uwagę na czwarty wiersz, bo to najczęstsza pułapka. Hosting zaproponował naszemu klientowi przywrócenie kopii sprzed infekcji. Odmówiliśmy, bo kopia zawierała tę samą wtyczkę w tej samej wersji. Wcześniejsza reinstalacja z kopii skończyła się ponownym przejęciem strony w ciągu dziesięciu godzin.

Odwirusowanie zrobione porządnie: kolejność, która działa

Kolejność ma znaczenie i różni się od intuicyjnej. Nie zaczyna się od kasowania.

  1. Kopia dowodowa przed jakąkolwiek zmianą. Pliki, baza, logi. Bez tego nie ustalisz, co się stało, a przy sklepie internetowym może to być potrzebne do oceny obowiązków wynikających z RODO.
  2. Ustalenie wektora z logów. Bierzesz datę powstania złośliwego pliku i czytasz logi serwera z tej minuty. To jedyny krok, który naprawdę kończy sprawę, i jednocześnie ten, który najczęściej się pomija.
  3. Zamknięcie drogi wejścia. Aktualizacja albo usunięcie podatnego komponentu. Dopiero teraz sprzątanie ma sens.
  4. Usunięcie złośliwych plików i weryfikacja rdzenia oraz wtyczek sumami kontrolnymi, żeby wiedzieć, że nic więcej nie zostało podmienione.
  5. Przegląd kont i sesji. Usunięcie obcych administratorów, unieważnienie wszystkich sesji, wymiana kluczy szyfrujących.
  6. Przegląd bazy danych. Wpisy w opcjach, zaplanowane zadania, wtyczki wykonujące kod zapisany w bazie.
  7. Dopiero teraz rotacja haseł. Zmiana haseł przed zamknięciem drogi wejścia jest bezwartościowa. Atakujący z dostępem do serwera odczyta nowe albo wejdzie tą samą trasą.
  8. Utwardzenie i monitoring. Blokada wykonywania skryptów w katalogu z plikami użytkowników, wyłączenie edytora plików, zapora, kontrola przez kolejne dwa tygodnie.
  9. Porządki w Google. Zgłoszenie usunięcia podstawionych adresów z indeksu i sprawdzenie listy zweryfikowanych właścicieli witryny, bo atakujący potrafi się tam dopisać.

Jest jeszcze jeden szczegół techniczny, który warto sprawdzić u siebie, nawet jeśli nie masz infekcji. Jeżeli korzystasz z zapory typu Cloudflare, upewnij się, że adresu IP Twojego serwera nie da się otworzyć bezpośrednio, z pominięciem zapory. U naszego klienta dało się, co czyniło wszystkie reguły bezużytecznymi. Sprawdzisz to jednym poleceniem:

curl -k -H "Host: twojadomena.pl" https://ADRES_IP_SERWERA/

Jeśli w odpowiedzi zobaczysz swoją stronę zamiast błędu, zapora jest do obejścia.

Ile kosztuje usunięcie wirusa ze strony WordPress

Podajemy liczby wprost, bo w tej branży bywa z tym różnie.

Odwirusowanie zajmuje nam od 2 do 8 godzin, w zależności od typu infekcji i stanu zastanego. Przy naszej stawce 200 zł netto za godzinę daje to:

Sytuacja Czas Koszt netto
Prosta infekcja: pojedynczy backdoor, znany wektor, mała strona wizytówkowa 2-3 h 400-600 zł
Typowa infekcja: kilkanaście plików, wektor do ustalenia z logów, sklep średniej wielkości 4-6 h 800-1200 zł
Złożona: nawracająca infekcja, wiele wtyczek, konta atakującego, spam w indeksie Google 6-8 h 1200-1600 zł

Co jest w tej cenie: kopia dowodowa, ustalenie wektora z logów, usunięcie infekcji, weryfikacja sumami kontrolnymi, przegląd kont i bazy, utwardzenie konfiguracji, raport z opisem tego, co się stało, oraz kontrola po pracach.

Czego w niej nie ma: odzyskiwania pozycji w Google, jeśli spam był indeksowany miesiącami, przebudowy strony opartej o porzucone wtyczki bez wsparcia oraz stałej opieki po zakończeniu prac. Te rzeczy wyceniamy osobno i mówimy o nich przed rozpoczęciem, nie po.

Na rynku znajdziesz oferty od 299 zł. Różnica polega na tym, co dokładnie kupujesz. Za najniższą stawkę zwykle dostajesz przeskanowanie automatem i usunięcie tego, co wykrył, bez analizy logów. Jeśli wektor pozostanie otwarty, zapłacisz drugi raz. Nasza wycena obejmuje ustalenie drogi wejścia, bo bez tego cała reszta jest tymczasowa.

Dla porównania: dobowy przestój sklepu, ostrzeżenie Google przed wejściem na stronę albo utrata pozycji zbudowanych przez lata kosztują wielokrotnie więcej niż najdroższy wariant z tabeli. Nie piszemy tego, żeby straszyć, tylko dlatego, że proporcja jest naprawdę taka.

Jak zabezpieczyć stronę, żeby infekcja nie wróciła

Jeśli używasz WPMU DEV Dashboard albo innej wtyczki do zdalnego zarządzania, sprawdź jej wersję ręcznie na stronie producenta. Nie polegaj na liście aktualizacji w panelu, bo dodatki spoza katalogu WordPressa na niej nie występują. Potem przeszukaj logi serwera pod kątem parametru, którego ta wtyczka używa do przyjmowania poleceń z zewnątrz. W naszym przypadku wystarczyło wyszukać frazę wpmudev-hub.

Poza tym:

  • Zrób listę płatnych wtyczek spoza katalogu WordPressa i sprawdzaj ich wersje raz w miesiącu. To one wypadają z normalnego cyklu aktualizacji.
  • Usuwaj, nie wyłączaj. Wyłączona wtyczka nadal leży na serwerze i jej pliki bywają dostępne z sieci.
  • Zablokuj wykonywanie skryptów PHP w katalogu z plikami użytkowników.
  • Wyłącz edytor plików w panelu stałą DISALLOW_FILE_EDIT.
  • Włącz uwierzytelnianie dwuskładnikowe dla wszystkich kont administratora.
  • Przeglądaj listę użytkowników raz w miesiącu. Znasz każde konto z uprawnieniami administratora?
  • Wyszukaj site:twojadomena.pl w Google i przejrzyj wyniki poza pierwszą stroną.
  • Zadbaj o monitoring zmian plików, żeby dowiedzieć się o nowym pliku tego samego dnia, nie po tygodniu.

Co zrobić teraz

Jeśli Twoja strona wraca do stanu zainfekowanego mimo czyszczenia, zacznij od trzech rzeczy, zanim zapłacisz komukolwiek za kolejne sprzątanie.

  1. Wypisz płatne wtyczki spoza katalogu WordPressa i porównaj ich wersje z tymi na stronach producentów. Panel Ci tego nie pokaże.
  2. Poproś hosting o logi z dnia, w którym pojawił się złośliwy plik. Nie o skan, o logi. To w nich jest odpowiedź.
  3. Sprawdź listę administratorów i zweryfikowanych właścicieli w Search Console. Jedno obce konto w którymkolwiek z tych miejsc unieważnia całe czyszczenie.

Jeżeli któryś z tych punktów wygląda niepokojąco albo nie masz jak go sprawdzić, napisz do nas i opisz sytuację. Zaczynamy od bezpłatnego przeglądu, który pozwala ocenić skalę i podać konkretną cenę przed rozpoczęciem prac, a nie po. Odwirusowanie z ustaleniem drogi wejścia to u nas od 2 do 8 godzin, czyli od 400 do 1600 zł netto.

Jeśli szukasz stałej opieki nad infrastrukturą, spójrz na obsługę informatyczną firm, a bieżące sprawy techniczne prowadzimy przez system zgłoszeń serwisowych. Komunikat „wirusy usunięte" mówi o plikach, nie o dostępie, i to jest jedyna rzecz, którą warto zapamiętać z tego tekstu.

Źródła

  1. GitHub Advisory Database, CVE-2026-15459, obejście uwierzytelniania w WPMU DEV Dashboard: github.com/advisories.
  2. Wordfence Threat Intelligence, analiza podatności wtyczki wpmudev-updates: wordfence.com.
  3. Patchstack, CVE-2026-76581, obejście logowania przez mechanizm SSO: patchstack.com.
  4. WPScan Vulnerability Database, CVE-2026-16051: wpscan.com.
  5. Forum wsparcia WordPress.org, wątek opisujący ten sam łańcuch ataku u innych użytkowników: wordpress.org/support.
  6. Google Search Central, usuwanie adresów URL z wyników wyszukiwania: developers.google.com.