Blog technologiczny od 2014 · 1 115 wpisów
RSS

Dlaczego boty pukają pod /admin? Sprawdziłem dokładniej logi 404

W Google Analytics zaczęło mi się pokazywać dużo odwiedzin z tytułem „strony nie znaleziono”. Sprawdziłem logi pod kątem statusów HTTP 404 oraz to, kto naprawdę uderza pod takie URL-e jak /admin, /wp-login.php i /xmlrpc.php.

Od jakiegoś czasu w Google Analytics widziałem regularne wejścia na stronę „nie znaleziono”. Nie jakieś tam pojedyncze przypadki — powtarzający się wzorzec. Zainstalowałem więc wtyczkę logującą błędy 404 i po czterech dniach miałem 1231 wpisów.

Jedną z pierwszych rzeczy, jakie rzuciły mi się w oczy, to był adres /admin. Wyprzedzał w statystykach nawet zwykłe, nieistniejące linki do starych zdjęć z wpisów. Problem w tym, że na highlab.pl nigdy nie było panelu pod tym adresem — panel WordPressa siedzi tam, gdzie zawsze, czyli pod /wp-admin/.

Trolololo

Ten wpis specjalnie umieściłem pod adresem /admin. Trochę na złość botom ale też w celach edukacyjnych.

Z tego artykułu dowiesz się:
  • /admin był najczęściej odpytywanym, nieistniejącym adresem na blogu — ale nie w postaci rozłożonego w czasie skanowania, tylko jednego 19-minutowego epizodu.
  • /wp-login.php i /wp-admin/ nigdy nie trafiają do logu 404, bo naprawdę istnieją — trzeba ich szukać w surowych logach serwera.
  • xmlrpc.php dostał realny, świeży atak: 60 żądań z jednego adresu w niecałe 11 minut, podszywających się pod Jetpacka.
  • To samo zjawisko, tylko w większej skali, potwierdzają niezależne badania (SANS ISC, Stony Brook University).

Co właściwie siedzi w tych 1231 requestach

Zanim zacząłem doszukiwać się ataków, sprawdziłem, ile z tego to „szum” — nieistniejące obrazki po latach zmian w treściach, ikonki, których szuka przeglądarka czy boty wyszukiwarek robiące swoje. Rozkład dzienny wyglądał tak (ostatni dzień to tylko wycinek do godziny eksportu):

23 września
217
24 września
516
25 września
411
26 września (do 7:49)
87
Adres Żądania
/admin 69
/.well-known/traffic-advice 48
/apple-touch-icon.png 16
/wp-content/uploads/…/xiaomi-redmi-note-9-pro…jpg 16
/apple-touch-icon-precomposed.png 15
/wp-content/uploads/…/xiaomi-redmi-note-11…jpg 15
/wp-content/uploads/…/xiaomi-redmi-note-10-pro…jpg 15
/wp-content/uploads/…/xiaomi-redmi-note-10s…jpg 15
/wp-content/uploads/…/xiaomi-redmi-note-9…jpg 14
/wp-content/uploads/2019/05/cropped-image-32×32.png 12

Większość tej listy to pozostałości po starych wpisach na blogu: usunięte zdjęcia oraz favicony, których szuka Safari na iPhonie (apple-touch-icon), oraz /.well-known/traffic-advice — to nie żaden atak, tylko standard sprawdzany przez przeglądarki wspierające Private Relay/prefetch proxy. Tylko jeden wpis na tej liście nie ma żadnego wytłumaczenia „to normalne”: /admin.

Z 1231 żądań 404 udało mi się rozpoznać po adresie User-Agent 98 wejść (ok. 8%) od znanych botów:

  • Bingbot (44),
  • Googlebot (33),
  • YandexBot (17),
  • Applebot i Facebook External Hit (po 2).

To ruch, który da się nazwać „nieszkodliwym” z dużą pewnością — te firmy podają się za to, kim naprawdę są. Cała reszta to mieszanka botów udających przeglądarki i tego, co opisuję niżej.

/admin samo w sobie nie jest luką bezpieczeństwa. Jest po prostu jednym z najbardziej przewidywalnych adresów, jakie automat może sprawdzić bez żadnej wcześniejszej wiedzy o mojej stronie (ani innych).

69 żądań /admin  w 19 minut

Kiedy rozłożyłem te 69 wejść na /admin na osi czasu, to okazało się, że to nie rozkłada się równomiernie — tak jak się tego spodziewałem po przeczytaniu typowych opisów tego zjawiska. To był jeden, skoncentrowany skan: 23 września, między 18:51 a 19:10.

404-logs.json — filtr: url=/admin
18:51:xx  POST /admin  ref: https://highlab.pl/wp-admin/
18:52:xx  POST /admin  ref: https://highlab.pl/wp-admin/
18:52:xx  POST /admin  ref: https://highlab.pl/wp-admin/
…65 kolejnych wpisów, ten sam wzorzec…
19:10:xx  POST /admin  ref: https://highlab.pl/wp-admin/

Po dokładniejszej analizie okazało się, że:

  1. Metoda POST, nie GET. To nie jest „sprawdzenie, czy strona istnieje” — to próba wysłania danych pod ten adres.
  2. Identyczny referrer za każdym razem — https://highlab.pl/wp-admin/, czyli nagłówek sugerujący, że żądanie „przyszło” z panelu WordPressa. Nagłówek Referer wysyła klient, więc równie dobrze może być spreparowany.
  3. Ubogi zestaw User-Agentów — 69 żądań, ale tylko 10 różnych wartości, wszystkie to wersje Chrome/Firefox/Safari z okolic 2021 roku. Prawdziwa przeglądarka nie zmienia swojej tożsamości co request.
Czego z samych logów HTTP nie da się stwierdzić

Nie mam dowodu, że ktoś logował się do panelu, ani że doszło do włamania. Mogę tylko powiedzieć, że wzorzec (skondensowany czas, powtarzalna metoda, ten sam referrer, wąska pula fałszywych przeglądarek) jest charakterystyczny dla jakiegoś automatycznego skanu, a nie dla organicznego ruchu użytkownika klikającego w linki.

Innymi słowy: gdybym patrzył tylko na sumaryczną liczbę „69 żądań do /admin w cztery dni”, opowiedziałbym sobie historię o ciągłym, rozproszonym skanowaniu z całego internetu. Rozbicie na oś czasu pokazuje coś innego — jeden, krótki epizod, bardziej podobny do uruchomienia konkretnego narzędzia niż do tła, które leci bez przerwy.

A co z prawdziwymi ścieżkami WordPressa?

Tu jest niuans, którego nie było widać w samym logu 404 od wtyczki: /wp-admin/ i /wp-login.php naprawdę istnieją na moim serwerze, więc nigdy nie trafiają do logu błędów — WordPress odpowiada im poprawnym kodem 200 albo przekierowaniem, nie 404. Żeby je zobaczyć, musiałem zajrzeć do surowych logów serwera (access.log) z ostatnich dwóch dni.

Adres Metoda Żądania Unikalne IP
/wp-admin/admin-ajax.php POST/GET 163 2
/xmlrpc.php POST 79 4
/wp-admin/ GET 4 1
/wp-login.php POST 2 2

admin-ajax.php to fałszywy trop — te 163 żądania z zaledwie 2 adresów IP to najpewniej zwykły ruch WordPressa (heartbeat, licznik komentarzy) oraz mój własny, gdy przeglądam stronę zalogowany. Nie każde trafienie w coś z /wp-admin/ w nazwie to atak.

Jednakże /xmlrpc.php, to już konkretny przykład tego, o czym mówię w tym artykule. 60 z 79 żądań przyszło z jednego adresu IP (z Indii, wg pola geo w logu), w ciągu niecałych 11 minut — od 09:04:56 do 09:15:25. Każde żądanie identyfikowało się jako  Jetpack/WordPress.com, ale za każdym razem z innym wariantem wersji i losową, nieistniejącą domeną w nagłówku:

access.log — 122.170.192.39
09:04:56  POST /xmlrpc.php  200  UA: Jetpack by WordPress.com (Jetpack 13.0; WordPress 6.3)
09:05:06  POST /xmlrpc.php  200  UA: WordPress.com; https://wordpress.com
09:05:17  POST /xmlrpc.php  200  UA: Jetpack/13.0; WordPress/6.3; http://site27117189.com
09:05:27  POST /xmlrpc.php  200  UA: WordPress.com; https://wordpress.com
09:05:37  POST /xmlrpc.php  200  UA: Jetpack/12.0; WordPress/6.4; http://site59128473.com
…w sumie 60 żądań, 32 różne warianty UA, odstępy ~10 sekund…

To nie jest hipotetyczne zagrożenie z listy w poradniku bezpieczeństwa — to konkretny wpis w moim własnym logu z tego tygodnia. xmlrpc.php pozwala m.in. na specjalną metodę XML-RPC system.multicall, która w jednym żądaniu HTTP umożliwia sprawdzenie wielu par login/hasło naraz. Stąd właśnie jego popularność jako celu prób logowania i ataków typu brute-force czy pingback spam, mimo że sam adres nie zwraca 404 i nie widać go w typowym raporcie „strona nie znaleziona”.

Skąd boty w ogóle znają te adresy?

Boty nie muszą wcześniej znać struktury mojej strony. Wystarczy, że mają listę popularnych ścieżek i sprawdzają je po kolei, niezależnie od tego, na jaki adres akurat trafił:

typowa-lista-botow.txt
/admin
/wp-login.php
/administrator/
/xmlrpc.php
/user/login
/login.php
/wp-admin/install.php

Ten sam skrypt bez zmian potrafi sprawdzić WordPressa, Joomlę i pięć innych systemów — po prostu odpytuje kolejne adresy z gotowej listy, aż któryś zwróci coś innego niż 404. Jeśli trafi, dopiero wtedy „wie”, z czym ma do czynienia, i sięga po kolejny, bardziej specyficzny zestaw ścieżek.

Czy to znaczy, że ktoś próbuje się włamać?

Niekoniecznie — i to jest rozróżnienie, które warto mieć w głowie patrząc na własne logi:

  • Rekonesans (discovery). GET /admin — sprawdzenie, czy endpoint w ogóle istnieje. Sam w sobie nieszkodliwy, choć irytujący w logach.
  • Próba logowania. POST /wp-login.php albo POST /xmlrpc.php z danymi logowania — to już realna próba uwierzytelnienia, choćby ślepa.
  • Wykorzystanie luki. Żądanie celujące w konkretną, znaną podatność konkretnej wtyczki czy wersji CMS-a.

Sam request do /admin — nawet gdy jest ich 69 w kwadrans — pasuje do pierwszej kategorii (rekonesans). Nie mam dowodu na drugą ani trzecią. Ale POST zamiast GET, sfałszowany referrer i rotowane UA to już zachowanie bliższe zautomatyzowanemu narzędziu niż nieszkodliwemu robotowi indeksującemu.

Czy to zjawisko jest powszechne poza moim blogiem?

Tak, i są na to konkretne, publikowane dane z dłuższych eksperymentów niż mój czterodniowy wycinek.

1. SANS Internet Storm Center — dwanaście miesięcy jednej domeny

Jan Kopřiva z SANS ISC opublikował w 2020 roku zestawienie najczęściej odpytywanych ścieżek na domenie, która nigdy nie hostowała żadnego z popularnych CMS-ów. Mimo to boty regularnie sprawdzały typowe adresy:

Adres Żądania
/wp-login.php 1140
/admin/ 189
/administrator/ 104
/wp-admin/install.php 82
/login.php 48

Innymi słowy: /admin/ był drugim najczęściej sprawdzanym adresem na stronie, która nigdy nie miała pod nim niczego — dokładnie ten sam wzorzec co u mnie, tylko rozłożony na cały rok zamiast na jeden wieczór.

2. Aristaeus — sto przynęt, siedem miesięcy, 26,4 mln żądań

Znacznie większą skalę pokazuje praca badaczy ze Stony Brook University („Good Bot, Bad Bot: Characterizing Automated Browsing Activity”, IEEE S&P 2021). Zbudowali 100 stron-przynęt (honeysite’ów) opartych o WordPressa, Joomlę, Drupala, phpMyAdmin i Webmin — domeny, które nigdy wcześniej nie istniały, więc cały trafiający tam ruch musiał pochodzić od botów.

Żądań w 7 miesięcy
26,4 mln
Unikalnych adresów IP
287 017
Ruchu ocenione jako złośliwe
57%
POST do wp-login/xmlrpc
90,3%

Wśród najczęściej żądanych adresów na honeysite’ach WordPressa: xmlrpc.php, wp-login.php, /wp-admin/ i /administrator/. Dokładnie te same adresy, które widzę u siebie.

Dlaczego to jest dobra wiadomość

Skoro strony, które nigdy nie istniały i nigdy nie miały żadnego linku prowadzącego do nich z zewnątrz, dostają miliony takich żądań — to jasny dowód, że ten ruch nie zależy od tego, czy ktoś w ogóle wie o moim blogu. To odbywa się ciągle, niezależnie od popularności konkretnej strony.

Czy zmiana /admin na coś innego zwiększa bezpieczeństwo?

Zmiana adresu panelu z /wp-admin na coś w stylu /moj-tajny-panel-x7 to klasyczny przykład tzw. security through obscurity. Sama w sobie niczego nie zabezpiecza — jeśli ktoś pozna nowy adres (np. z linku w kodzie źródłowym, z pliku sitemap albo po prostu przez przypadek), nadal może pod niego wejść tak samo, jak pod stary.

Ale ma praktyczną, mierzalną zaletę: ogranicza ilość szumu generowanego przez automaty, które nie znają tego konkretnego adresu — czyli właśnie te wszystkie skrypty sprawdzające gotowe listy popularnych ścieżek. Mniej takiego ruchu to:

  • mniej prób logowania do odfiltrowania,
  • czytelniejsze logi (łatwiej zauważyć coś naprawdę nietypowego),
  • mniejsze obciążenie serwera generowane przez requesty, które i tak nie miały szans się powieść.

Czyli: „mniej przewidywalny adres” ≠ „zabezpieczony panel”, ale też nie jest to działanie bez żadnej wartości — po prostu adresuje inny problem niż właściwe zabezpieczenie logowania.

Czego nauczyły mnie te cztery dni logów

  1. Nie każde 404 pochodzi od człowieka — ale też nie każde jest atakiem; spora część to zwykłe nieistniejące linki i favicony.
  2. /admin był u mnie jednym skoncentrowanym epizodem (69 POST-ów w 19 minut).
  3. Realne ścieżki WordPressa (/wp-admin/, /wp-login.php) nie trafiają do logu 404, bo naprawdę istnieją — trzeba po nie sięgnąć do surowych logów serwera.
  4. xmlrpc.php okazał się u mnie realnym, aktywnym celem: 60 żądań z jednego adresu w niecałe 11 minut, podszywających się pod Jetpacka.
  5. Ten sam wzorzec, tylko w większej skali, potwierdzają niezależne badania (SANS ISC, Aristaeus/Stony Brook) — to nie jest wina „popularności” mojego bloga.
  6. Request do /admin nie oznacza automatycznie próby włamania — to zwykle najpierw rekonesans.

FAQ

01Dlaczego boty próbują wejść na /admin?+
Bo to jeden z najbardziej przewidywalnych adresów panelu administracyjnego w internecie — automat sprawdza go „na wszelki wypadek”, bez wcześniejszej wiedzy o konkretnej stronie.
02Czy request na /admin oznacza próbę włamania?+
Sam w sobie zwykle nie. To najczęściej rekonesans — sprawdzenie, czy endpoint istnieje. Próbą logowania staje się dopiero, gdy niesie dane uwierzytelniające (request POST z loginem i hasłem).
03Dlaczego akurat WordPress jest tak często skanowany?+
Bo napędza ogromną część stron w internecie i ma przewidywalną strukturę — te same ścieżki (wp-login.php, xmlrpc.php, wp-admin) działają identycznie na milionach instalacji, więc jeden skrypt atakujący skaluje się bez zmian.
04Czy xmlrpc.php trzeba wyłączyć?+
Jeśli nie korzystasz z funkcji, które go wymagają (część pingbacków, niektóre integracje typu Jetpack), ograniczenie dostępu do niego zmniejsza ilość ataku — to widać wprost w moich własnych logach z tego tygodnia.
Źródła

Jan Kopřiva, „What pages do bad bots look for?”, SANS Internet Storm Center, 1 sierpnia 2020 — isc.sans.edu/diary/26414.
Xigao Li, Babak Amin Azad, Amir Rahmati, Nick Nikiforakis, „Good Bot, Bad Bot: Characterizing Automated Browsing Activity”, IEEE Symposium on Security and Privacy 2021, Stony Brook University.

Opublikowano · Znalazłeś błąd? Napisz
Piotr Cichosz
Autor

Od ponad 10 lat jestem zaangażowany w świat elektroniki użytkowej, zdobywając szeroką wiedzę i doświadczenie w testowaniu oraz recenzowaniu najnowszych technologii. Moja kariera obejmuje pracę w wiodących firmach technologicznych, gdzie specjalizowałem się…

Czytaj dalej
← Poprzedni Recenzja TRUST GXT 873 ACIRA MINI TRI-MODE WIRELESS – 60% to zupełnie inne doświadczenie