Spis treści
Zgłoszenie brzmiało niewinnie: „strona się dziwnie zachowuje". W praktyce klient miał na jednym koncie hostingowym (jeden login, jeden panel administracyjny) prawie 50 domen opartych o WordPress — głównie strony poszczególnych wydarzeń sportowych. Zaczęliśmy audyt od dwóch zgłoszonych stron. Po pełnym przeglądzie konta okazało się, że aktywna infekcja obejmuje siedemnaście serwisów naraz.
To pierwsza rzecz, którą warto zapamiętać, jeśli prowadzisz więcej niż jedną stronę: współdzielone konto hostingowe oznacza brak izolacji między stronami. Włamanie na jedną stronę, jeśli atakujący zdobędzie dostęp na poziomie całego konta (a nie tylko pojedynczej instalacji WordPressa), otwiera automatycznie wszystkie pozostałe — nawet te ważniejsze, lepiej utrzymane serwisy.
Zanim przejdziemy do szczegółów tego konkretnego przypadku, krótko o tym, na co reagować u siebie. W tym incydencie pojawiły się niemal wszystkie klasyczne sygnały ostrzegawcze:
wp-content/uploads — folder przeznaczony na obrazki i dokumenty, nigdy na kod wykonywalny.Czym jest mechanizm: plik o niewinnie brzmiącej nazwie, umieszczony w specjalnym folderze wtyczek ładowanych automatycznie (tzw. must-use plugins — WordPress uruchamia je zawsze, przy każdym wczytaniu strony, bez możliwości wyłączenia z panelu administracyjnego, co czyni je ulubionym miejscem atakujących do ukrywania złośliwego kodu). Ten konkretny plik wstrzykiwał do treści stron ukryte linki do kasyn online (tzw. black-hat SEO spam) i nadpisywał plik sitemap.xml, żeby wyszukiwarka szybciej zaindeksowała spamowe podstrony.
Jaki skutek: odwiedzający widzieli normalną stronę, ale roboty Google indeksowały setki dodatkowych, niewidocznych dla człowieka podstron promujących hazard online — co bezpośrednio szkodzi reputacji domeny w wyszukiwarce i może skończyć się ręczną karą od Google.
Dlaczego to ważne dla ustalenia skali: ten sam plik, identyczny co do bajtu, pojawił się na kilkunastu różnych domenach w tej samej minucie. To dowód na tzw. ruch boczny (lateral movement) — atakujący nie włamywał się osobno na każdą stronę, tylko skopiował plik wszędzie naraz, bo miał dostęp na poziomie całego konta hostingowego (FTP, SSH albo panel), a nie tylko do jednej podatnej wtyczki.
Czym jest mechanizm: to była druga, osobna i znacznie bardziej wyrafinowana rodzina złośliwego kodu niż mu-plugin z linkami w stopce (opisany w punkcie 1). Wstrzyknięty do plików motywu skrypt podmieniał na kilkunastu konkretnych podstronach — np. /zapisy/, /kontakt/, /pomoc/ — całą treść strony, ale wyłącznie wtedy, gdy odwiedzającym był robot wyszukiwarki, a nie prawdziwy człowiek.
Jak dokładnie rozróżniał boty od ludzi: najpierw sprawdzał nagłówek User-Agent przeglądarki pod kątem słów kluczowych („googlebot", „bingbot", „bot", „spider", „crawler" i kilkunastu innych). To jednak łatwo oszukać, więc skrypt miał drugi, znacznie sprytniejszy poziom weryfikacji: dla ruchu podającego się za Googlebota sprawdzał adres IP przez odwrotne zapytanie DNS (reverse DNS), żeby upewnić się, że to naprawdę serwery Google, a nie ktoś podszywający się pod ich nazwę w nagłówku. Dopiero po takiej dwustopniowej weryfikacji decydował, co pokazać.
Co się działo dalej: jeśli odwiedzającym był potwierdzony bot, skrypt pobierał w tle gotową treść z zewnętrznego serwera atakującego i podstawiał ją zamiast prawdziwej zawartości strony — łącznie z własnym nagłówkiem HTTP „200 OK", żeby wszystko wyglądało dla wyszukiwarki jak normalna, poprawnie działająca strona. Zwykły odwiedzający, klikający w te same adresy z przeglądarki, nigdy tego nie widział — dostawał oryginalną, niezmienioną treść.
Jaki skutek: Google indeksował realne podstrony Twojej strony — z prawdziwym adresem, prawdziwą historią i reputacją domeny — jako strony promujące konkretne marki hazardowe, bo dokładnie taką treść dostarczał mu ten skrypt przy każdych odwiedzinach. Właściciel strony, patrząc na nią w przeglądarce, nie widział niczego niepokojącego.
Czym jest mechanizm: webshell to złośliwy skrypt (najczęściej plik PHP), który po wgraniu na serwer daje atakującemu graficzny panel do przeglądania, edytowania i uruchamiania dowolnych plików bezpośrednio z poziomu przeglądarki — bez logowania się do WordPressa. Znaleźliśmy kilka wariantów tego samego narzędzia, część podszywająca się pod pliki rdzenia WordPressa (różnica jednej litery w nazwie od legalnego pliku systemowego, np. wp-comments-posts.php zamiast prawdziwego wp-comments-post.php). Jeden z serwisów miał wręcz jawnie zainstalowaną wtyczkę-webshell w standardowym katalogu wtyczek, widoczną w panelu WordPressa jak każda inna.
Jaki skutek: pełny odczyt, zapis i wykonywanie dowolnych plików na serwerze — to praktycznie równoznaczne z fizycznym dostępem do serwera.
Czym jest mechanizm: w plikach startowych powłoki konta systemowego (uruchamianych automatycznie przy każdym logowaniu przez SSH) doklejona była jedna, pozornie niewinna linijka: fragment zakodowany w base64 (popularny sposób ukrywania treści kodu przed pobieżnym przeglądem), który po zdekodowaniu ściągał i uruchamiał dodatkowy kod — mechanizm typu reverse shell, dający atakującemu zdalny dostęp do terminala konta w dowolnym momencie. Data modyfikacji tych plików była ręcznie cofnięta o kilka lat wstecz, a sama złośliwa linijka zawierała ukryte znaki sterujące terminala, przez co była praktycznie niewidoczna przy zwykłym podglądzie zawartości pliku w konsoli.
Dlaczego to poważniejsze niż zwykły webshell: to już nie jest „dziura w jednej wtyczce", którą naprawia się aktualizacją. To trwały dostęp na poziomie systemu operacyjnego konta hostingowego, przeżywający nawet całkowite usunięcie i ponowną instalację WordPressa.
Czym jest mechanizm: defacement to podmiana widocznej treści strony przez atakującego, często jako „wizytówka" udanego włamania. Na jednej ze stron zmieniona została nazwa serwisu zapisana w bazie danych na komunikat w stylu „hacked by [pseudonim grupy]" — widoczne to było w tytule karty przeglądarki i bezpośrednio w wynikach wyszukiwania Google od momentu włamania.
Dlaczego nikt tego nie zauważył wcześniej: strona wizualnie działała normalnie — zmieniony był tylko jeden, mało widoczny na co dzień parametr w panelu ustawień ogólnych. To dobry przykład na to, że „strona wygląda dobrze" i „strona jest bezpieczna" to dwie zupełnie różne rzeczy.
Czym jest mechanizm: atakujący dodawał się jako administrator nie tylko w samym WordPressie, ale też w usłudze Google Search Console powiązanej z zaatakowanymi domenami.
Dlaczego to spójne z resztą ataku: kontrola nad Search Console pozwala między innymi przesyłać własne mapy witryny (sitemap) i zgłaszać konkretne adresy URL do ponownego zaindeksowania — dokładnie to, czego potrzeba, żeby spamowe podstrony z linkami do kasyn faktycznie zaczęły się pojawiać w wynikach wyszukiwania. To potwierdza, że cały atak był zorganizowaną kampanią black-hat SEO, nastawioną na zysk z pozycjonowania stron hazardowych, a nie przypadkowym wandalizmem.
Żaden pojedynczy błąd nie tłumaczy skali tego incydentu — złożyło się na to kilka rzeczy naraz, i każda z nich osobno jest jednym z najczęstszych powodów, dla których strony na WordPressie są hakowane:
Co ciekawe i pocieszające zarazem: rdzeń WordPressa na żadnej ze stron nie był zmodyfikowany. Atakujący tylko dokładał własne pliki, nie majstrował przy oryginalnym kodzie systemu. To istotnie ułatwiło późniejsze czyszczenie — mogliśmy zaufać sumom kontrolnym oficjalnych plików rdzenia i szukać wyłącznie tego, co nie powinno tam się znajdować.
Przy tej skali infekcji łatwo o pokusę, żeby robić wszystko naraz. To jeden z częstszych błędów przy samodzielnym czyszczeniu strony po włamaniu. Kolejność, którą przyjęliśmy, i którą rekomendujemy jako dobrą praktykę niezależnie od skali:
Ważna zasada praktyczna: nic nie usuwaliśmy od razu. Każdy podejrzany plik trafiał najpierw do kwarantanny — zmiana nazwy pliku, odebranie wszystkich uprawnień dostępu — i dopiero po pełnej weryfikacji, że to rzeczywiście złośliwy kod (a nie na przykład legalna, ale nietypowo wyglądająca wtyczka), następowało trwałe usunięcie. Przy tej skali fałszywy alarm i przypadkowe skasowanie czegoś ważnego kosztowałoby więcej niż jeden dodatkowy dzień weryfikacji.
Najciekawsza — i najbardziej pouczająca — część tej historii wydarzyła się już po formalnym zamknięciu głównego incydentu. Nasz własny system monitoringu, ustawiony na cykliczne skanowanie całego konta hostingowego, wykrył trzy tygodnie później dwa pliki noszące dokładnie te same sygnatury złośliwego kodu, które rzekomo już wyczyściliśmy.
Po dokładnym sprawdzeniu okazało się, że to nie były nowe infekcje. To były stare, zapomniane kopie zapasowe — katalogi utworzone przypadkiem podczas samego incydentu (prawdopodobnie przez kogoś próbującego ręcznie zabezpieczyć dane w trakcie trwającego ataku), leżące fizycznie obok właściwego, aktywnego folderu strony. Nasze pierwotne czyszczenie skupiło się — słusznie z punktu widzenia priorytetów, ale niekompletnie — wyłącznie na żywych, publicznie dostępnych wersjach stron. Te osierocone kopie stały z boku, poza pierwszym radarem, i przez trzy tygodnie nikt ich nie tknął.
Wniosek praktyczny: pełne posprzątanie po incydencie bezpieczeństwa nie kończy się na wyczyszczeniu tego, co jest aktualnie „online". Trzeba też przeszukać dosłownie wszystko, co fizycznie leży na koncie hostingowym — stare kopie zapasowe, katalogi z datą w nazwie, archiwa po migracjach — bo każdy z nich może zawierać dokładnie ten sam złośliwy kod, gotowy do ponownego wykorzystania, jeśli tylko ktoś przypadkiem go przywróci albo zostawi bez nadzoru.
Sprawdź listę użytkowników/administratorów w WordPressie (Użytkownicy → Wszyscy użytkownicy) pod kątem nieznanych kont, przejrzyj katalog wp-content/uploads pod kątem plików .php (nie powinno ich tam być w ogóle), porównaj tytuł strony widoczny w Google z tym, co faktycznie ustawiłeś, i sprawdź w Google Search Console, czy nie ma nagłego wzrostu zaindeksowanych stron o tematyce niezwiązanej z Twoim biznesem.
Webshell to nie „wirus" w klasycznym rozumieniu, tylko narzędzie administracyjne wgrane bez Twojej wiedzy — daje atakującemu pełną kontrolę nad plikami serwera z poziomu przeglądarki, podobnie jak legalny panel hostingowy. Nie replikuje się samo, ale pozwala na wgranie kolejnych, dowolnych narzędzi.
Nie, i to jeden z najczęstszych błędów. Jeśli atakujący zostawił backdoora w plikach na serwerze (a nie tylko zalogował się przez odgadnięte hasło), samo nowe hasło go nie zablokuje. Trzeba najpierw znaleźć i usunąć wszystkie złośliwe pliki, a dopiero potem rotować dane dostępowe.
Nie ma jednej sztywnej liczby, ale każda dodatkowa strona na współdzielonym koncie zwiększa powierzchnię ataku wszystkich pozostałych. Dla stron o realnej wartości biznesowej (sprzedaż, dane klientów, marka) warto rozważyć osobne konta hostingowe albo przynajmniej osobnych użytkowników systemowych z ograniczonymi uprawnieniami.
Nie musisz prowadzić kilkudziesięciu stron na jednym koncie, żeby ten scenariusz był dla Ciebie istotny. Pięć rzeczy, które warto sprawdzić niezależnie od skali Twojego biznesu:
Jeśli nie jesteś pewien odpowiedzi na któreś z powyższych pytań, to dobry sygnał, żeby zrobić profesjonalny audyt bezpieczeństwa, zanim zrobi to za Ciebie ktoś inny — na Twój koszt i koszt reputacji Twojej marki.