Pytanie rzadko pojawia się bez powodu. Serwer zaczął działać wolniej, hostingodawca napisał o ruchu wychodzącym albo w poczcie znalazło się powiadomienie o logowaniu, którego nikt nie wykonywał. Potem zaczyna się najbardziej nieprzyjemna część: nie wiadomo, co sprawdzać i w jakiej kolejności, a pierwszy odruch — skasować wszystko i postawić od nowa — jest niemal zawsze przedwczesny.

Poniżej kolejność sprawdzania, która zajmuje jakieś dwadzieścia minut i w większości przypadków daje jednoznaczną odpowiedź. Idzie od najtańszego do najdroższego: najpierw to, co widać od razu, potem to, co wymaga porównania.

Krok pierwszy: kto się logował

Zacznijmy od logowań. Jeśli ktoś obcy dostał się do środka, prawie na pewno wszedł przez SSH i został ślad.

last -20
lastb | head -20
who

last pokaże ostatnie udane logowania, lastb — nieudane, who — kto jest zalogowany w tej chwili. Liczy się nie liczba, lecz kształt. Tysiące nieudanych prób z adresów, które nigdy nie wracają, to zwykłe tło; dzieje się tak na każdym publicznym adresie nieprzerwanie i nic nie znaczy.

Niepokojące jest co innego:

  • udane logowanie z adresu, pod którym nie ma nikogo z zespołu;
  • logowanie na nazwę użytkownika, której nikt nie zakładał;
  • nieudane próby na nazwę, która na tej maszynie faktycznie istnieje — to znaczy, że ktoś zna listę użytkowników, a nie leci ze słownika;
  • sesja otwarta w tej chwili, której nikt z zespołu nie otwierał.

Osobno warto sprawdzić, czy nie pojawiły się obce klucze. Plik ~/.ssh/authorized_keys to najczęstszy sposób na utrwalenie dostępu: hasło można zmieniać dowolnie wiele razy, klucz zostanie.

cat ~/.ssh/authorized_keys
sudo cat /root/.ssh/authorized_keys

Każdy wiersz to czyjś dostęp. Jeśli nie da się powiedzieć czyj, należy uznać go za obcy.

Krok drugi: co zmieniło się w systemie

Włamanie prawie zawsze zostawia ślady na dysku: podmieniony plik wykonywalny, dopisany wiersz w konfiguracji, nowy plik w katalogu serwera WWW. Sprawdzanie tego wzrokiem nie ma sensu — potrzebny jest wzorzec.

W Debianie i Ubuntu wzorzec już istnieje: każdy pakiet zna sumy kontrolne swoich plików.

sudo apt install debsums
sudo debsums -c

Polecenie wypisze pliki różniące się od tego, co zainstalowała dystrybucja. Część znalezisk będzie uzasadniona — pliki konfiguracyjne w /etc po to właśnie istnieją, żeby je zmieniać. Natomiast zmieniony plik wykonywalny w /usr/bin, /usr/sbin czy /bin na serwerze, którego nikt nie ruszał ręcznie, to już inna rozmowa.

Drugie źródło to świeże pliki tam, gdzie ich być nie powinno. Webshell zwykle leży w katalogu przesyłanych plików i wygląda jak niewinny .php:

find /var/www -type f -name '*.php' -mtime -14 -ls

Czternaście dni to tylko punkt wyjścia; należy wstawić okres, w którym na pewno nic nie było publikowane.

Krok trzeci: co wychodzi na zewnątrz

Zhakowany serwer rzadko przejmuje się dla niego samego. Używa się go: do rozsyłania spamu, do kopania kryptowalut, do wchodzenia w cudze sieci, do trzymania cudzych plików. Wszystko to tworzy połączenia wychodzące, których wcześniej nie było.

ss -tulpn
ss -tp state established

Pierwsze polecenie pokaże, co nasłuchuje, drugie — co jest zestawione teraz. Czytać należy kolumnę z procesem. Wątpliwości budzą: nieznany proces nasłuchujący na 0.0.0.0; połączenia wychodzące na wysokie porty do adresów, z którymi aplikacja nie ma nic wspólnego; a zwłaszcza proces uruchomiony z /tmp albo /dev/shm — z tych katalogów nie uruchamia się nic legalnego.

Przy okazji warto spojrzeć na obciążenie. Koparka zdradza się tym, że procesor jest zajęty bez przerwy, a witryna nie cieszy się żadną popularnością.

Jeśli oznaki się potwierdzą

Pierwszy odruch to szybko posprzątać: usunąć obcy klucz, zabić proces, skasować plik. Tak robić nie należy, bo zniszczy się to, po czym można by później zrozumieć, którędy wszedł. A jeśli tego nie zrozumiemy, wróci — i to być może jutro.

Kolejność, która chroni i dane, i obraz sytuacji:

  1. Zrobić migawkę dysku u hostingodawcy, jeśli jest taka możliwość. To jedyny krok, którego później nie da się powtórzyć.
  2. Odciąć maszynę od sieci albo zamknąć wszystko poza własnym adresem IP — ale nie wyłączać. Przy wyłączeniu tracimy listę procesów i otwarte połączenia, a to połowa dowodów.
  3. Zapisać dzienniki na zewnątrz: /var/log/auth.log, dzienniki serwera WWW, wynik trzech powyższych poleceń.
  4. Dopiero teraz ustalać, jak uzyskano dostęp.

Instalacja od zera to właściwe zakończenie, jeśli dostęp uzyskano z uprawnieniami roota. Żadne czyszczenie nie daje gwarancji, że nic nie zostało. Ale instalowanie od nowa bez zrozumienia przyczyny nie ma sensu: ta sama dziura wróci na świeży system.

Żeby pytanie nie pojawiało się nagle

Wszystko powyższe to jednorazowe ręczne sprawdzenie i odpowiada na pytanie „co dzieje się w tej chwili”. Kłopot w tym, że zadaje się je zwykle późno: kiedy hostingodawca już napisał albo witryna przestała działać.

Każde z tych sprawdzeń istnieje jako osobne narzędzie, które potrafi obserwować stale: nieudane logowania — fail2ban, zmiany plików — AIDE, integralność pakietów — debsums, otwarte porty — regularna migawka ss. Zainstalować je osobno nie jest trudno; trudniej przyzwyczaić się do codziennego czytania sześciu różnych wyników — dlatego w praktyce nikt ich nie czyta.

Na tym właśnie polega sens zebranego panelu: te same dane, ale na jednej stronie i z historią, żeby „wczoraj było inaczej” było widoczne bez osobnej wyprawy. Poniżej strony demonstracyjne pokazujące, jak to wygląda w całości.