Na drugiej witrynie tego samego klienta infekcja była aktywna: złośliwy skrypt nakładał na stronę fałszywe okno weryfikacji bezpieczeństwa, a atakujący miał własne konto administratora. Tym razem udało mi się ustalić, którędy wszedł — przez znaną lukę w WordPressie, której poprawka nie dotarła na stronę, bo aktualizacje były wyłączone.
Problem
Klient przekazał mi kopię drugiej zainfekowanej strony, działającej na tym samym koncie hostingowym co witryna, którą czyściłem wcześniej. To rozbudowana strona firmowa zbudowana w popularnym kreatorze stron z płatnym dodatkiem, z katalogiem oferty opartym na wtyczce sklepu internetowego i kilkoma modułami napisanymi na zamówienie. Zakres był ten sam: analiza, usunięcie infekcji, uruchomienie strony na kopii i paczka do wdrożenia na wyczyszczony serwer.
Choć obie strony należą do jednego klienta, nie zakładałem z góry, że to ten sam incydent. Złośliwy kod, czas włamania i sposób działania okazały się inne. Nie mam też dowodów, że za oboma stoi ten sam sprawca.
Co ustaliłem
Wśród wtyczek była jedna o nazwie łudząco podobnej do znanej wtyczki marketingowej. Była aktywna i do nagłówka każdej strony dodawała zaciemniony skrypt JavaScript. Zdekodowałem go bez uruchamiania: skrypt nakładał na stronę pełnoekranową ramkę podpisaną jako kontrola bezpieczeństwa i wczytywał do niej treść z serwera atakującego. Ten wzorzec jest znany z kampanii fałszywych weryfikacji, które nakłaniają odwiedzających do uruchomienia polecenia na własnym komputerze. Treści z serwera atakującego celowo nie pobierałem, więc nie wiem, co dokładnie wyświetlała.
W bazie było też dodatkowe konto administratora o losowej nazwie. Zapisane sesje wskazywały na logowania z kilku różnych adresów, ostatnie tuż przed rozpoczęciem moich prac.
Tym razem dziennik błędów pozwolił odtworzyć sposób wejścia. Widać w nim serię nietypowych zapytań do interfejsu API strony, próby wstrzyknięcia kodu do bazy danych i, w tej samej sekundzie, utworzenie nowego konta. Ślady odpowiadają publicznie opisanej podatności w rdzeniu WordPressa w wersji używanej przez stronę. W bazie pozostał też artefakt typowy dla gotowego narzędzia wykorzystującego tę lukę. Do jej wykorzystania nie trzeba było znać żadnego hasła.
Poprawka była dostępna przed atakiem, ale strona jej nie dostała: wtyczka do zarządzania aktualizacjami miała wyłączone wszystkie aktualizacje. Ten przebieg oceniam jako wysoce prawdopodobny. Bez logów serwera nie da się go potwierdzić w stu procentach.
Porównanie z kopią zapasową sprzed około ośmiu miesięcy pokazało, że wtedy infekcji nie było. Rdzeń, wtyczki z oficjalnego repozytorium, motywy, moduły pisane na zamówienie, przesłane pliki i baza danych nie zawierały innych śladów. Znalazłem natomiast dwa pliki, które nie powinny być publicznie dostępne: archiwum kopii zapasowej z pełną bazą danych oraz dziennik błędów.
Co zrobiłem
- Przed zmianami wykonałem kopie plików i bazy. Złośliwą wtyczkę i dziennik błędów przeniosłem do kwarantanny, a archiwum kopii zapasowej poza katalog publiczny.
- Usunąłem konto atakującego, pozostałości po ataku i wszystkie sesje logowania; wygenerowałem nowe klucze zabezpieczające.
- Wyłączyłem wtyczkę blokującą aktualizacje i zaktualizowałem WordPressa do najnowszej wersji, a wtyczkę sklepu razem z migracją jej danych. Sprawdziłem, że edytor stron działa na nowej wersji.
- Kreator stron zaktualizowałem do najnowszego wydania zgodnego z posiadaną wersją płatnego dodatku. Aktualizacja samego dodatku wymaga licencji, więc zostawiłem ją do wykonania na produkcji.
- Wyłączyłem dwie nieużywane wtyczki, zmieniłem adres logowania do panelu i zablokowałem edycję plików z poziomu panelu.
Jedna rzecz wymagała korekty w trakcie prac. Motyw nadrzędny był wcześniej modyfikowany bezpośrednio, więc jego aktualizacja na kopii nadpisała te zmiany. Wychwyciłem to podczas testów i przywróciłem motyw z kopii zapasowej. Zaleciłem, żeby nie aktualizować motywu, dopóki zmiany nie zostaną przeniesione do motywu potomnego.
Rezultat
Na kopii lokalnej wszystkie 40 opublikowanych adresów działało poprawnie, moduły pisane na zamówienie wyświetlały się, a edytor stron wczytywał się bez błędów. Paczkę sprawdziłem importem do pustej bazy danych i uruchomieniem strony z jej plików. Do wdrożenia trzeba już tylko wpisać hasło do bazy.
Testy dotyczyły kopii, nie serwera produkcyjnego. Ponieważ w przekazanej kopii infekcja była aktywna, klient dostał listę działań do wykonania od razu na serwerze, jeszcze przed wdrożeniem paczki: usunięcie konta i wtyczki atakującego, aktualizację WordPressa, zmianę haseł i usunięcie publicznie dostępnych plików. Do zrobienia pozostaje aktualizacja płatnego dodatku, który w obecnej wersji ma znane podatności.
Wnioski
- Wyłączone aktualizacje to otwarte drzwi. Tutaj bezpośrednio umożliwiły atak na lukę, dla której poprawka już istniała. Warto włączyć przynajmniej automatyczne poprawki bezpieczeństwa.
- Silne hasła są konieczne, ale nie zastąpią aktualizacji — do tej luki hasło nie było potrzebne.
- Kopie zapasowe i dzienniki trzymane w katalogu publicznym to gotowy prezent dla atakującego. Ich miejsce jest poza stroną.
- Zmiany w motywie trzeba umieszczać w motywie potomnym, bo inaczej znikną przy aktualizacji.
- Strony na jednym koncie hostingowym dzielą ryzyko: włamanie na jedną może dać dostęp do plików pozostałych. Zalecam przegląd wszystkich stron na koncie, choć w tym przypadku nie mam dowodu, że oba incydenty są powiązane.
Aktualizacje w Twoim WordPressie są wyłączone, „żeby nic się nie popsuło”?
Sprawdzę, czy strona nie jest już zainfekowana, usunę złośliwy kod i bezpiecznie przeprowadzę aktualizacje, testując je najpierw na kopii witryny. Porozmawiajmy o zabezpieczeniu Twojej strony albo zobacz, jak wygląda odwirusowanie strony WordPress.