Malware w WordPressie wraca po usunięciu, gdy ma więcej niż jedną kopię i każda potrafi odbudować pozostałe. Usunięcie jednej nic nie daje, bo reszta ją przywraca. Trzeba znaleźć wszystkie miejsca startu (mu-plugins, pliki drop-in, .user.ini, wp-config.php, bazę danych), usunąć je w jednym przebiegu i od razu włączyć monitoring zmian w plikach. Poniżej dwa przypadki z naszych interwencji i lista miejsc, których nie sprawdza ani wp core verify-checksums, ani typowa wtyczka bezpieczeństwa.
Jak wyglądała samoodtwarzająca się fałszywa wtyczka?
Na stronie działała wtyczka, której nikt nie instalował. Po przejrzeniu serwera znaleźliśmy ją w 11 miejscach, w tym:
- w katalogu
wp-content/mu-plugins/, czyli wśród wtyczek ładowanych zawsze i niewidocznych na zwykłej liście wtyczek, - w plikach drop-in w
wp-content(pliki typuobject-cache.phpczyadvanced-cache.php, które WordPress ładuje sam, jeśli istnieją), - w pliku
.user.iniz dyrektywąauto_prepend_file.
Do tego 35 wierszy w tabeli wp_options. Kopie odtwarzały się nawzajem: usunięcie jednej lokalizacji kończyło się jej odbudową z pozostałych.
Czym są mu-plugins, drop-iny i .user.ini?
Wszystkie te miejsca uruchamiają kod PHP bez wiedzy właściciela strony, a większość nie zostawia śladu na liście wtyczek.
| Miejsce | Kiedy się uruchamia | Czy widać w panelu? |
|---|---|---|
wp-content/mu-plugins/ | przy każdym ładowaniu WordPressa, nie da się go wyłączyć z panelu | tylko na osobnej liście w ekranie wtyczek, łatwo przeoczyć |
drop-iny w wp-content/ | gdy WordPress znajdzie plik o zastrzeżonej nazwie, np. przy cache | na osobnej liście w ekranie wtyczek, bez opisu, co robi kod |
.user.ini | przed każdym skryptem PHP, jeszcze przed WordPressem | nie |
wp-config.php | przy każdym żądaniu do WordPressa | nie |
tabela wp_options | gdy kod z plików odczyta zapisaną kopię | nie |
Najgroźniejszy jest .user.ini. Działa na poziomie PHP, więc wyłączenie wszystkich wtyczek, zmiana motywu czy nawet podmiana rdzenia WordPressa niczego nie zmienia. PHP-FPM czyta ten plik dla katalogu, w którym leży skrypt, a dyrektywa auto_prepend_file dokleja wskazany plik przed każdym wywołaniem PHP. Dodatkowo PHP trzyma odczytane ustawienia w pamięci przez czas z user_ini.cache_ttl (domyślnie 300 sekund), więc po usunięciu pliku złośliwy kod może działać jeszcze kilka minut. Wygląda to tak, jakby usuwanie nie działało.
Masz ten sam problem? Sprawdzimy mu-plugins, drop-iny, konfigurację PHP i bazę, zanim cokolwiek skasujemy. Opisz sytuację →
Dlaczego wp core verify-checksums nie wykrył infekcji?
Bo nie do tego służy. wp core verify-checksums porównuje pliki rdzenia WordPressa z sumami kontrolnymi z wordpress.org. Zgłosi zmieniony wp-includes/load.php, ale nie zobaczy nowego pliku w mu-plugins, drop-inu w wp-content ani .user.ini w katalogu głównym. Rdzeń może być czysty, a strona zarażona.
Podobnie wp plugin verify-checksums --all: sprawdza wtyczki z repozytorium wordpress.org, a mu-plugins i drop-inów nie obejmuje. Oba polecenia są przydatne, ale „Success” z nich nie oznacza czystej strony. Oznacza czysty rdzeń.
Jak znaleźć wszystkie kopie malware?
Zacznij od miejsc, których nie sprawdzają skanery rdzenia. Te polecenia tylko czytają, niczego nie zmieniają:
# pliki .user.ini i php.ini z auto_prepend_file w całym katalogu strony
find . \( -name ".user.ini" -o -name "php.ini" \) -exec grep -l "auto_prepend_file" {} +
# zawartość mu-plugins i drop-iny w wp-content
ls -la wp-content/mu-plugins/
ls -la wp-content/*.php
# co WordPress ładuje jako mu-plugins i drop-iny
wp plugin list --status=must-use,dropin
# koniec wp-config.php: wszystko po linii z wp-settings.php jest podejrzane
tail -n 20 wp-config.phpNie każde trafienie to malware. Firewall Wordfence też używa auto_prepend_file (plik wordfence-waf.php), więc sprawdź, na jaki plik wskazuje dyrektywa i co jest w środku.
W bazie szukaj opcji, których nie potrafisz przypisać do żadnej znanej wtyczki, oraz nietypowo dużych wartości. Prefiks tabel może być inny niż wp_:
SELECT option_name, LENGTH(option_value) AS rozmiar
FROM wp_options
ORDER BY rozmiar DESC
LIMIT 30;Długi ciąg znaków bez spacji w opcji lub transiencie to sygnał, że w bazie leży zakodowana kopia pliku. Zanim cokolwiek usuniesz, zrób kopię plików i bazy, bo będzie potrzebna do ustalenia, którędy weszło malware.
Jak usunąć malware, żeby nie wróciło?
Wszystko naraz. Kolejność, którą stosowaliśmy w tym przypadku:
- Inwentarz. Lista wszystkich 11 lokalizacji w plikach i 35 wierszy w bazie, spisana przed pierwszym kasowaniem.
- Neutralizacja .user.ini na poziomie PHP. W konfiguracji PHP ustawiliśmy
user_ini.filename =(pusta wartość), żeby PHP w ogóle przestał czytać pliki .user.ini. Wtedy nawet odtworzony plik nic nie zrobi. Po zmianie trzeba przeładować PHP-FPM. - Usunięcie wszystkich kopii w jednym przebiegu. Pliki i wiersze w bazie w ciągu jednej operacji, bez przerw, w których pozostałe kopie mogłyby odbudować usunięte.
- Monitoring integralności plików co 10 minut. Skrypt porównuje pliki z bazą odniesienia i alarmuje przy nowych lub zmienionych plikach, także w mu-plugins, drop-inach i .user.ini.
; php.ini albo konfiguracja puli PHP-FPM
user_ini.filename =Uwaga: wyłączenie .user.ini dotyczy wszystkich stron obsługiwanych przez tę konfigurację PHP. Jeśli któraś legalnie ustawia w nim np. limit pamięci, przenieś to ustawienie do php.ini lub konfiguracji puli.
Co, jeśli usunięty plik wraca po kilku minutach?
Szukaj kodu, który go zapisuje. Drugi przypadek, z innej strony: plik dropper wracał po każdym usunięciu. Przyczyną był kod dopisany na końcu wp-config.php. Sprawdzał, czy dropper istnieje, a jeśli nie, zapisywał go ponownie z kopii base64 trzymanej w bazie danych jako transient.
Kasowanie samego pliku nie mogło zadziałać, bo wp-config.php wykonuje się przy każdym wejściu na stronę. Usunąć trzeba razem kod z wp-config.php, transient z bazy i sam plik. Kolejne kopie pliku to objaw. Źródłem jest kod, który je zapisuje.
Czy wtyczka bezpieczeństwa wystarczy?
Na taką infekcję zwykle nie. Skanery wtyczek dobrze rozpoznają znane pliki, ale działają wewnątrz WordPressa, więc nie mają wpływu na .user.ini, który wykonuje się przed nimi. Gorzej radzą sobie też z kopiami zakodowanymi w bazie. Po ich „wyczyszczeniu” zostaje kopia, która odbudowuje resztę.
Jeśli malware wróciło więcej niż raz, nie usuwaj kolejnych plików na ślepo. Każda próba bez pełnej listy lokalizacji daje infekcji czas na odbudowę, a przy okazji zaciera ślady. Ogólny przebieg sprzątania po włamaniu opisaliśmy w tekście o tym, jak rozpoznać i usunąć wirusa z WordPressa. Jeśli wolisz to zlecić, ASAPDevs robi usuwanie malware z WordPressa z inwentarzem wszystkich kopii i monitoringiem po sprzątaniu, a sklepy na WooCommerce bierzemy też w stałą opiekę. Gdy strona leży i nie ma na co czekać, dzwoń na pogotowie IT.
