Strona główna · Blog · Strony WWW
Włamanie na stronę WordPress – jak je wykryć, gdy panel nie pokazuje problemu?

Strona WordPress może zostać zhakowana, mimo że panel administracyjny działa prawidłowo i nie pokazuje żadnych podejrzanych zmian. Na stronie firmowej jednego z naszych klientów napastnik podmienił podstrony Kontakt i Blog na indonezyjskie kasyno. Przez 5 dni nikt tego nie zauważył, a Google kierował tam osoby szukające kasyn.
Włamanie odkryliśmy przypadkiem w Google Search Console. Przed nim strona zbierała średnio 73 kliknięcia dziennie, a w szczytowym dniu aż 1242. Analiza plików wykazała, że napastnik miał dostęp do serwera już od 11 dni. Poniżej znajdziesz opis tego przypadku oraz wskazówki, jak wykryć włamanie i ukryte złośliwe pliki, których nie widać w WordPressie.
Jak napastnik ukrył kasyno przed WordPressem?
Zamiast zmieniać treść w WordPressie, napastnik 27 sierpnia utworzył na serwerze dwa katalogi: /kontakt/ i /blog/. W każdym umieścił własny plik index.html ze stroną kasyna oraz sitemap.xml. Oryginalne strony pozostały nietknięte.
Wykorzystał standardową regułę WordPressa w pliku .htaccess: Warunki RewriteCond %{REQUEST_FILENAME} !-f oraz !-d kierują żądanie do WordPressa tylko wtedy, gdy na serwerze nie ma już pliku ani katalogu o tej ścieżce.
Ponieważ podstawione katalogi istniały, serwer wyświetlał kasyno bez uruchamiania WordPressa.

Reguła .htaccess, dzięki której podstawione katalogi miały pierwszeństwo przed stronami WordPressa.
W edytorze WordPressa nadal widoczna była prawidłowa strona Kontakt. Jej edycja lub usunięcie niczego by nie naprawiły, trzeba było usunąć podstawione katalogi przez FTP. Wtyczki bezpieczeństwa działające wewnątrz WordPressa również mogły nie wykryć podmiany, bo żądania omijały cały system.

Dwa katalogi z plikami kasyna, które zastąpiły oryginalne podstrony bez zmiany treści w WordPressie.
Po czym poznać, że coś jest nie tak?
Pierwszy sygnał znaleźliśmy w Google Search Console. Kliknięcia gwałtownie rosły, choć liczba wyświetleń prawie się nie zmieniała. Między 27 a 31 sierpnia podstrona /kontakt/ zebrała 2642 kliknięcia, a /blog/ kolejne 1428, niemal wyłącznie z wyszukiwań nazw dwóch indonezyjskich kasyn. Po usunięciu podstawionych plików ruch od razu wrócił do normy.

Gwałtowny wzrost kliknięć przy niemal niezmienionej liczbie wyświetleń. Po usunięciu kasyna ruch wrócił do normy.
Na własnej stronie zacznij od zakładki Zapytania w Search Console. Szukamy obcych fraz i podejrzanych adresów spoza mapy witryny. Warto też sprawdzić wyniki Google przez site:twojadomena.pl i użyć narzędzia Sprawdzanie adresu URL. Podejrzaną podstronę pobieramy poleceniem curl i porównujemy jej treść z edytorem WordPressa.
Sprawdziliśmy 8 kombinacji przeglądarki i źródła wejścia. Za każdym razem wyświetlało się kasyno, więc nie był to cloaking, czyli pokazywanie różnych treści różnym odwiedzającym. W kodzie znaleźliśmy też obcy znacznik weryfikacji Search Console, ale napastnik nie został właścicielem usługi. Raport Problemy dotyczące bezpieczeństwa nie ostrzegł nas o włamaniu, ponieważ pokazuje zagrożenia dopiero wtedy, gdy Google sam je rozpozna.
Jak znaleźć ukryte pliki?
Lista wtyczek WordPressa nie pokazała pierwszej furtki. Napastnik umieścił ją 20 sierpnia w wp-content/plugins/wp-cfg/configs.php. Pozwalała wykonywać polecenia na serwerze, ale nie miała nagłówka Plugin Name, więc nie było jej wśród aktywnych ani wyłączonych wtyczek. Szukanie fragmentów eval(base64_decode, gzinflate czy FilesMan też nic nie dało. Kod był czytelny, z komentarzami po indonezyjsku.
22 sierpnia napastnik dodał trzy menedżery plików pod nazwami przypominającymi pliki WordPressa. Bez tajnego parametru zwracały błąd 404.
Nie ograniczaj szukania do dnia, w którym zauważyłeś problem. Furtki znaleźliśmy dopiero przez porównanie plików z sumami kontrolnymi publikowanymi przez WordPress.org dla każdej wersji i języka. Takie porównanie wykrywa pliki zmienione i dodatkowe, których nie ma w oryginalnej paczce. Furtki należały do tej drugiej grupy. Po sprzątaniu 2797 z 2798 plików rdzenia było zgodnych, a jedyna różnica w version.php wynikała z polskiej wersji WordPressa.

Porównanie z oficjalnymi sumami kontrolnymi wykrywa zmienione i dodatkowe pliki WordPressa.
Taką kontrolę wykonasz przez SSH poleceniami wp core verify-checksums –include-root oraz wp plugin verify-checksums –all dla wtyczek z repozytorium. Bez SSH pobierz pliki przez FTP i porównaj je z sumami dostępnymi pod api.wordpress.org/core/checksums/1.0/, podając wersję i język instalacji. Wersję WordPressa odczytaj z wp-includes/version.php, a nie z parametru ver= w adresach plików, który może dotyczyć wtyczki lub motywu.
Jak teraz pilnujemy tego codziennie?
Po tym włamaniu zbudowaliśmy narzędzie, które codziennie automatycznie sprawdza 16 stron klientów, a raz w tygodniu wykonuje dokładniejsze kontrole. Dostajemy jeden raport ze statusem każdej strony: w porządku, do sprawdzenia albo nie udało się sprawdzić. U klienta nic nie instalujemy, żadnej wtyczki. Korzystamy z FTP, panelu WordPressa i sprawdzania strony z zewnątrz. Hasła zostają u nas, wysyłamy tylko gotowy raport.
Monitoring porównuje wyniki z poprzednim dniem i alarmuje wyłącznie o nowych zmianach. Podejrzany plik pobieramy ponownie, żeby wykluczyć błąd pobierania. Pliki wykonywalne .php, .phtml i .phar sprawdzamy we wszystkich katalogach, również w cache.
| Kontrola | Jak działa | Co wyłapuje |
| Pliki (codziennie) | Porównujemy przez FTP listę plików z poprzednim dniem | Nowe pliki PHP i HTML, katalogi wtyczek i motywów, zmiany w wp-config.php, .htaccess i .user.ini. |
| Podstrony (codziennie) | Pobieramy adresy z mapy witryny, w sklepach również koszyk i kasę. Porównujemy tytuły, domeny i tekst. | Obce skrypty i domeny, spam, japońskie i chińskie znaki, ukryte linki, niedostępne strony. |
| Konta (codziennie) | Porównujemy użytkowników w panelu WordPressa. | Nowe konta i podniesienie uprawnień. |
| Konfiguracja (codziennie) | Testujemy xmlrpc.php, ?author= i wejście z Google na telefonie. | Możliwość logowania przez XML-RPC, ujawnione loginy i ukryte przekierowania. |
| Widoczność i domena (codziennie) | Sprawdzamy noindex, robots.txt, Google Safe Browsing, SSL, domenę, DNS i pocztę. | Blokady indeksowania, ostrzeżenia Google, SSL ważny krócej niż 14 dni, domenę do odnowienia za mniej niż 30 dni i zmiany konfiguracji. |
| Wtyczki i luki (raz w tygodniu) | Porównujemy wtyczki z paczkami WordPress.org, a wersje wtyczek i motywów z bazą podatności Wordfence, skanując kopię plików u siebie. | Obce lub zmienione pliki i nowe luki o wysokiej lub krytycznej wadze. |
| Googlebot (raz w tygodniu) | Pobieramy 12 adresów jako człowiek i Googlebot, porównując tytuły i rozmiary. | Różnice między wersjami stron. |

Codzienny raport z monitoringu 16 stron ze statusem każdej kontroli.
Bez FTP możemy sprawdzić tylko część wtyczek na podstawie publicznych plików readme.txt. Z zewnątrz widać od 5% do połowy zainstalowanych dodatków, ponieważ te działające wyłącznie w panelu nie zostawiają śladu w kodzie strony. Płatnych wtyczek nie mamy też z czym porównać. Pełna kontrola wymaga więc dostępu do plików serwera. Taki monitoring wykryłby pierwszą furtkę z opisanego włamania następnego ranka, czyli 11 dni wcześniej.
Co zrobić, gdy włamanie się potwierdzi?
Zanim przywrócisz kopię zapasową, ustal najwcześniejszy ślad napastnika. Na stronie firmowej każda kopia od 20 sierpnia zawierała furtkę, a w sklepie zainfekowane były kopie od 16 sierpnia do 20 września. Przywrócenie takiej kopii ponownie otworzyłoby napastnikowi dostęp do strony. Na stronie firmowej nie ustaliliśmy sposobu włamania, ponieważ brakowało logów.
Po usunięciu złośliwych plików zmieniamy hasła do WordPressa, FTP, hostingu i bazy danych, bo furtka pozwalała odczytać również hasło do bazy. Wymieniamy klucze bezpieczeństwa w wp-config.php, co wylogowuje wszystkie sesje, i sprawdzamy właścicieli oraz użytkowników w Google Search Console. Jeśli Google oznaczyło stronę jako niebezpieczną, prosimy o ponowne sprawdzenie, które może potrwać od kilku dni do kilku tygodni. Usunięcie kasyna ze strony nie oznacza jeszcze, że usunęliśmy z niej napastnika.


