Wybierz region
pl
  • PL
  • EN
Wydrukuj

#AdminCases, czyli gotowa solucja: Permanentnej inwigilacji ciąg dalszy czyli logowanie poleceń użytkowników via auditd

Z poprzedniego artykułu z serii #AdminCases wiemy, jak logować polecenia użytkowników, którzy używają powłoki BASH w Linux. Co jednak, gdy delikwenci (czytaj użytkownicy) nie używają tej powłoki albo w swoim niecnym działaniu chcą być cwańsi od cwaniaka (czytaj administratora) i spróbują obejść – świadomie lub nie – ułomności logowania w powłoce.

Może też najnormalniej w świecie admin stwierdził, że chce inny rodzaj logowania z powodu: Bo tak ???? Zrobimy logowanie za pomocą Auditd.

Będzie jeszcze jeden bonus specjalnie dla tych, którzy chcieliby poćwiczyć temat, a nie mają do tego środowisk. Stworzymy sobie środowisko testowe w postaci maszyn wirtualnych z różnymi systemami operacyjnymi Linux w VirtualBox utworzonymi za pomocą Vagrant innymi słowy dam Wam prosty przykład jak zautomatyzować sobie tworzenie środowisk, w tym przypadku do zabawy, a jak to później wykorzystacie to już Wasza w tym głowa.

Administrator czuwa – przynajmniej czujnym powinien być, jeżeli chce panować nad chaosem swojego podwórka, czyli serwerów, które są pod jego pieczą. Dlaczego warto logować polecenia użytkowników wytłumaczyłem w artykule Permanentna inwigilacja czyli jak w linuksie logować polecenia użytkowników. Teraz może opowiem o ułomnościach tego rozwiązania, bo taktowe posiada.

W pierwszej kolejności powłoka BASH powinna mieć ustawioną zmienną HISTCONTROL, odpowiadającą za zapis poleceń do historii powłoki, na wartość ignoredups w innym przypadku zapis do historii głupieje, gdy użytkownik poprzedzi polecenie spacją lub spacjami – najnormalniej nie będzie go widać, a chyba raczej zależy nam na tym, aby widoczne były jeżeli logowanie ma mieć jakiś sens (swoją drogą dla potwierdzenia tego, że nie bredzę  sprawdziłem ignoredups organoleptycznie celem potwierdzenia na 3 dystrybucjach). Jak to mówią to po pierwsze primo. Teraz drugie primo (po prawdzie secundo), o którym na wstępie powiedziałem: aby rozwiązanie działało użytkownik musi używać Bourne-Again Shell, a chociaż ta powłoka jest najpopularniejsza to przecież jest jeszcze kilka innych chociażby Korn lub też inne wynalazki. Po trzecie mamy zmienną PROMPT_COMMAND, którą jakaś cholera może deaktywować używając polecenia unset. No dobra, dość już marudzenia i dajmy alternatywę dla wspomnianego rozwiązania, która pozwoli nam nadal przeglądać, kto co popsuł nawet jak mamy sabotażystkę lub na sali jest jakiś cwaniak.

Wykorzystamy do tego Linux Auditing System. Czym jest ów system? Ano mówiąc łopatologicznie to taka funkcja kernela, która pozwala na rejestrowanie wywołań systemowych. Można tam znaleźć na przykład otwarcie pliku, zabicie procesu lub utworzenie połączenia sieciowego czy też jaka gadzina użyła jakiegoś polecenia (łącznie z Panem i władcą czyli root-em). Te dzienniki inspekcji mogą być używane do monitorowania systemów pod kątem podejrzanej aktywności. Zasadniczo to na temat tego co i jak można zdziałać w Linux Audit w szczegółach nie jest celem tego artykułu bo skupiamy się tutaj na logowaniu komend użytkowników, dlatego podam tylko kilka rzeczy, które warto wiedzieć na ten temat – w znaczeniu „co i gdzie się znajduje” i przejdziemy do meritum, a być może (korzystając z cytatu z filmu Vabank) „następną razą” zajmiemy się szczegółowym opisem opcji, praktyką jak je skonfigurować i do czego służą.

Kilka informacji odnośnie Linux Audit. Dla rodziny linux  Debian Audit nie jest instalowany domyślnie więc trzeba dociągnąć sobie pakiet auditd, te spod znaku Czerwonego Kapelusza (dla mniej wtajemniczonych Red Hat) winny mieć pakiet zainstalowany by default. Proces odpowiadający za zapis do logu to auditd. Co ma zostać zapisane konfigurujemy za pomocą reguł, a w jaki sposób to skonfigurować pokażę za chwilę na przykładzie tego co jest naszym celem – innymi słowy zapisać polecenia użytkowników (oczywiście tworów, które możemy monitorować jest naprawdę wiele jednak tutaj skupiamy się na jednym temacie). Konfiguracja Linux Audit znajduje się w katalogu /etc/audit i podstawowym plikiem konfiguracyjnym jest auditd.conf. Jak wygląda ów plik konfiguracyjny? Już pokazuję.

 

Jak można zauważyć mamy tutaj chociażby wskazanie, gdzie znajduje się log i jaką ma nazwę, a raczej to akurat warto wiedzieć, tym bardziej, że ta wiedza będzie nam potrzebna celem przeglądania zapisów jakie tam będą gromadzone. Widać też, że logi są rotowane i zachowywane domyślnie jest 5 logów. Jeżeli chcecie wiedzieć więcej to przeczytajcie dokumentacje lub miejcie nadzieję, że w przypływie ułańskiej fantazji znajdę czas na to, żeby pochylić się nad tematem i to szczegółowo opisać – ja osobiście wybrałbym pierwszą opcję ????

Wracając do auditd, żeby móc w końcu pokazać w jaki sposób logować polecenia i co jeszcze ważniejsze, w jaki sposób je odczytać w Linux Auditing System. Przeglądanie dzienników odbywa się za pomocą narzędzi ausearch lub aureport. Konfigurowanie systemu audytu lub reguł ładowania odbywa się za pomocą narzędzia auditctl. To na dzisiaj koniec teorii bo przecież jesteśmy praktykami i uczymy się właśnie poprzez praktyczne zastosowanie wiedzy tajemnej zatem zacznijmy tę walkę i zobaczmy, czy wrócimy z niej z tarczą czy też na tarczy.

Na początek definicje reguł, które to wskażą co ma być logowane, czyli damy rozkaz systemowi audytu, aby był łaskaw wrzucać do logu polecenia wykonane w systemie. Użyjemy polecenia auditctl na uprawnieniach użytkownika root (może być przez sudo), a konkretnie dwóch wywołań tego polecenia w następującej notacji:

auditctl -a exit,always -F arch=b32 -S execve -k allcmds

auditctl -a exit,always -F arch=b64 -S execve -k allcmds

Rozszyfrujmy co my właściwie zadeklarowaliśmy w tych definicjach:

-a exit, always – to najczęściej stosowana kombinacja, określamy tutaj listę do zalogowania oraz akcję jaka ma zostać wykonana. Lista exit utworzy zdarzenie po zakończeniu wywołania systemowego. Inne listy z których możemy skorzystać to: task, user i exclude. Akcja always odpowiada za wstawienie timestampu i zapis do logu.

-F arch=b64 oraz –F arch=b32 - określa filtr zdefiniowany przez klucz (arch), wartość (b64 i b32). Jeden filtruje tylko wywołania systemowe architektury 64-bitowej drugi dla 32-bitowej.

-S execve - określa wywołanie systemowe w naszym przypadku to wykonanie programu

-k allcmds – to tag służący do identyfikacji reguły.

Sprawdźmy teraz czy nasze reguły zostały zapisane. Do tego również użyjemy polecenia auditctl z tym, że skorzystamy z opcji –l:

Jeszcze jedna rzecz, o której trzeba pamiętać, a mianowicie, że reguły utworzone przy użyciu auditctl będą egzystowały tylko do momentu restartu maszyny, jeżeli chcemy aby działały permanentnie, nawet po restarcie to w katalogu /etc/audit/rules.d należy utworzyć plik konfiguracyjny np. cmds.rules z wpisami jak w listingu z opcji –l polecenia auditctl. 

I teraz możemy wykonać jakieś polecenie w systemie i zobaczymy czy znajdziemy je w logu i w jakiej notacji to będzie pokazane – uprzedzam, że ta jest taka, że mój wielce szanowny kolega auditd określa jako narzędzie dla masochistów z czym na pierwszy rzut oka można się zgodzić, ale jak już się wie czego szukać zaczyna to trochę lepiej wyglądać.

Wykonamy kilka poleceń, aby móc sprawdzić czy faktycznie widać co się zadziało. Dla przykładu: ls –l, ls –l qwe, rm q. Log możemy czytać na różne sposoby od edycji przez Vim czy też odczyt poleceniem less jednak, aby trochę było to bardziej przeformatowane i aby móc skorzystać z możliwości filtrowania mamy polecenie ausearch, którego użyjemy. Całe polecenie razem z opcjami będzie wyglądało w następujący sposób i zaraz wytłumaczę znaczenie wykorzystanych przeze mnie opcji, dorzucę jeszcze kilka innych, a resztę sobie doczytajcie.

sudo ausearch -ui vagrant -k allcmds -i

-ui vagrant to nic innego jak szukaj zdarzeń dla użytkownika vagrant (ja akurat takiego w tym przypadku używałem)

-k allcmds to szukaj po tagu allcmds

-i to interpretowanie elementów liczbowych na tekst (np. Timestamp czy też samego polecenia w logu w lini typu PROCTITLE

 

Zobaczmy jak wygląda efekt:

----

type=PROCTITLE msg=audit(06.03.2022 23:41:58.711:2067) : proctitle=ls --color=auto -l

type=PATH msg=audit(06.03.2022 23:41:58.711:2067) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=1020171 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=PATH msg=audit(06.03.2022 23:41:58.711:2067) : item=0 name=/usr/bin/ls inode=201350106 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=CWD msg=audit(06.03.2022 23:41:58.711:2067) : cwd=/var/log

type=EXECVE msg=audit(06.03.2022 23:41:58.711:2067) : argc=3 a0=ls a1=--color=auto a2=-l

type=SYSCALL msg=audit(06.03.2022 23:41:58.711:2067) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x1bf7d00 a1=0x1bf7be0 a2=0x1bf65e0 a3=0x7ffedd8d44e0 items=2 ppid=26389 pid=26817 auid=vagrant uid=vagrant gid=vagrant euid=vagrant suid=vagrant fsuid=vagrant egid=vagrant sgid=vagrant fsgid=vagrant tty=pts1 ses=90 comm=ls exe=/usr/bin/ls subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=allcmds

----

type=PROCTITLE msg=audit(06.03.2022 23:42:01.596:2068) : proctitle=ls --color=auto -l qwe

type=PATH msg=audit(06.03.2022 23:42:01.596:2068) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=1020171 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=PATH msg=audit(06.03.2022 23:42:01.596:2068) : item=0 name=/usr/bin/ls inode=201350106 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=CWD msg=audit(06.03.2022 23:42:01.596:2068) : cwd=/var/log

type=EXECVE msg=audit(06.03.2022 23:42:01.596:2068) : argc=4 a0=ls a1=--color=auto a2=-l a3=qwe

type=SYSCALL msg=audit(06.03.2022 23:42:01.596:2068) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x1bf5f80 a1=0x1b83040 a2=0x1bf65e0 a3=0x7ffedd8d44e0 items=2 ppid=26389 pid=26818 auid=vagrant uid=vagrant gid=vagrant euid=vagrant suid=vagrant fsuid=vagrant egid=vagrant sgid=vagrant fsgid=vagrant tty=pts1 ses=90 comm=ls exe=/usr/bin/ls subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=allcmds

----

type=PROCTITLE msg=audit(06.03.2022 23:42:08.190:2069) : proctitle=rm q

type=PATH msg=audit(06.03.2022 23:42:08.190:2069) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=1020171 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=PATH msg=audit(06.03.2022 23:42:08.190:2069) : item=0 name=/usr/bin/rm inode=201350129 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=CWD msg=audit(06.03.2022 23:42:08.190:2069) : cwd=/var/log

type=EXECVE msg=audit(06.03.2022 23:42:08.190:2069) : argc=2 a0=rm a1=q

type=SYSCALL msg=audit(06.03.2022 23:42:08.190:2069) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x1bfaa50 a1=0x1c39c10 a2=0x1bf65e0 a3=0x7ffedd8d44e0 items=2 ppid=26389 pid=26819 auid=vagrant uid=vagrant gid=vagrant euid=vagrant suid=vagrant fsuid=vagrant egid=vagrant sgid=vagrant fsgid=vagrant tty=pts1 ses=90 comm=rm exe=/usr/bin/rm subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=allcmds

----

type=PROCTITLE msg=audit(06.03.2022 23:42:12.051:2070) : proctitle=sudo ausearch -ui vagrant -k allcmds -i

type=PATH msg=audit(06.03.2022 23:42:12.051:2070) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=1020171 dev=fc:00 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=PATH msg=audit(06.03.2022 23:42:12.051:2070) : item=0 name=/usr/bin/sudo inode=204040013 dev=fc:00 mode=file,suid,111 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:sudo_exec_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0

type=CWD msg=audit(06.03.2022 23:42:12.051:2070) : cwd=/var/log

type=EXECVE msg=audit(06.03.2022 23:42:12.051:2070) : argc=7 a0=sudo a1=ausearch a2=-ui a3=vagrant a4=-k a5=allcmds a6=-i

type=SYSCALL msg=audit(06.03.2022 23:42:12.051:2070) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x1b80100 a1=0x1c20d80 a2=0x1bf65e0 a3=0x7ffedd8d44e0 items=2 ppid=26389 pid=26820 auid=vagrant uid=vagrant gid=vagrant euid=root suid=root fsuid=root egid=vagrant sgid=vagrant fsgid=vagrant tty=pts1 ses=90 comm=sudo exe=/usr/bin/sudo subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=allcmds

Jak widać jedno zdarzenie jest wielowierszowe gdzie zapisane są wszystkie informacje składające się na ten event. W linii typu PROCTITLE dla polecenia ausearch, gdy nie skorzystamy z opcji -i będzie zapis typu:

type=PROCTITLE msg=audit(1646610467.947:2079): proctitle=7375646F006175736561726368002D75690076616772616E74002D6B00616C6C636D6473

Jednak jeżeli opcja –i wystąpiła mamy zapisane nasze polecenie. Również w lini typu EXECVE z tym, że tam polecenie rozbite jest na poszczególne argumenty, dla przykładu:

argc=4 a0=ls a1=--color=auto a2=-l a3=qwe

Zawsze możemy skorzystać z grep-a, aby ograniczyć wyświetlenie całego śmietnika i zobaczyć tylko polecenia, które zostały wywołane:

Ergo mamy to co chcieliśmy osiągnąć i widzimy wykonane polecenia.

Ausearch ma wiele opcji dla przykładu, jeżeli chcielibyśmy skorzystać z konkretnego logu możemy użyć opcji –if, gdzie wskazujemy konkretny input file. Polecam man ausearch i lekturę tego co tam jest zawarte. To samo dotyczy auditctl i aureport. 

Jak widać znowu ponieśliśmy zwycięstwo i możemy się poklepać po plecach, że (używając eufemizmu) jesteśmy tacy jedwabiści i możemy nastroszyć pióra niczym paw skoro tak nam się to pięknie udało.

A teraz to o czym uprzedzałem na początku, czyli bonus ode mnie w gratisie czyli środowisko do testów budowane przy użyciu narzędzia Vagrant. Nieważne czy mówimy tutaj do pingwinowców czy okienkowców, bo działa na obu systemach. Nawet, o ile się nie mylę Ci spod znaku nadgryzionego jabłuszka też mogą z tego skorzystać.  Ten kto nie miał styczności z tym toolem niech rzuci okiem w jak banalnie prosty sposób można utworzyć sobie środowiska czy do testów, czy do developmentu. Wystarczy mieć zainstalowany Vagrant oraz VirtualBox, utworzyć katalog, zawartość poniższego źródła zapisać w katalogu jako plik o nazwie Vagrantfile i wykonać polecenie vagrant up. Sam Vagrant pobierze co ma do pobrania i stworzy konfigurację według zapisów z pliku konfiguracyjnego czyli – w naszym przypadku – 4 maszyny wirtualne, każda z innym systemem operacyjnym, z odpowiednimi konfiguracjami. Może innym razem zagłębię się w szczegóły odnośnie tego narzędzia. A i jeszcze jedno z systemem zostanie utworzony użytkownik vagrant (hasło jak nazwa użytkownika) i jeżeli nie chcemy posługiwać się hasłem wystarczy przy pomocy ssh-copy-id –i vagrant@ip_hosta wrzucić swoje klucze SSH i nie będzie darł japy o hasło.

(Uwaga, warto powiększyć :) )

Jeżeli ktoś w swoim lenistwie jest na poziomie expert i życzy sobie pobrać źródło to zapraszam wszystkich takowych pod adres github.com/aciek/aciek/blob/main/Vagrant/VagrantLinuxes/Vagrantfile.

Aby zniszczyć maszyny wirtualne wystarczy skorzystać z polecenia vagrant destroy będąc w katalogu, gdzie znajduje się Vagrantfile. Wyłączenie poprzez vagrant halt. Jeżeli chcesz sprawdzić stan maszyn to użyj vagrant status. Można też połączyć się z wirtualką za pomocą vagrant ssh nazwa_maszyny.

Tak wyglądał przyspieszony kurs narzędzia vagrant i mam nadzieję, że się podobał i trafił na podatny grunt w chęci poszerzania wiedzy … kurtyna :)

No dobrze, dość już tych podśmiewanek jednak mam cichą nadzieję, że do tego stopnia ułatwiłem Wam drogę do zabawy, że chociażby dla przyzwoitości albo z nudów zrobicie sobie test z tych rozwiązań i bawcie się przy tym przednio jako i ja się bawię.

Ave ;)


Adam Paszkiewicz

Adam aka aciek, Ekspert ds. Technologii z Asseco Warszawa. Z technologiami związany od okresu dojrzewania (a ten był dawno temu) ale gotować i żeglować też potrafi. Rzeczy niemożliwe realizuje od ręki, na cuda trzeba chwilę zaczekać. Uważa, że w życiu jak i w pracy dobrze mieć kupę radości ... z przewagą radości.


Wydrukuj