Używanie utmpdump do wykrywania manipulacji plikami logowań

nfsec.pl 1 rok temu

Z

narzędziem utmpdump spotkaliśmy się pierwszy razy przy okazji ściągawki z informatyki śledczej w wykrywaniu włamań dzięki linii poleceń Linuksa. W tym wpisie rozwinę trochę użycie tego narzędzia i pokażę jak można go użyć od strony defensywnej, jak i ofensywnej. Pozornie nieznane przez wielu polecenie utmpdump jest doskonałym narzędziem do wykrywania manipulacji na plikach logowań. jeżeli chodzi o system Linux to często możemy polegać na następujących trzech artefaktach w celu określenia czynności logowania i wylogowywania użytkowników:

  • /var/run/utmp – plik utmp pozwala odkryć informacje o tym, kto aktualnie korzysta z systemu.
  • /var/log/wtmp – plik wtmp rejestruje wszystkie logowania i wylogowania. Jego format jest dokładnie taki jak utmp, z tą różnicą, iż pusta nazwa użytkownika wskazuje na wylogowanie z powiązanego terminala. Co więcej, nazwa terminala „~” z nazwą użytkownika „shutdown” lub „reboot” wskazuje na zamknięcie lub ponowne uruchomienie systemu.
  • /var/log/btmp – plik btmp zawiera wszystkie złe próby logowania do systemu.

Ponieważ pliki utmp, wtmp i btmp zawierają dane logowania wszystkich użytkowników, są one głównym celem modyfikacji lub usuwania wpisów przez intruzów i złośliwe oprogramowanie. Wiele rodzajów malware dla systemu Linux po prostu usunie te pliki i zastąpi je plikami o zerowej długości bajtów. Bardziej wyrafinowani napastnicy podejmują próbę wyczyszczenia poszczególnych wpisów jednak jest to trudniejszy sposób na zacieranie śladów i łatwo go zauważyć.

Pliki *tmp mają format binarny, aby je odczytać użyjemy narzędzia utmpdump. W najbardziej podstawowej składni utmpdump pozwala nam gwałtownie zrzucić logi i zapisać je do późniejszego przejrzenia w formie tekstowej:

utmpdump /var/run/utmp utmpdump /var/log/wtmp utmpdump /var/log/btmp

Możemy również przekierować strumień wyjścia do innego pliku w celu archiwizacji artefaktów:

utmpdump /var/run/utmp > utmp.log utmpdump /var/log/wtmp > wtmp.log utmpdump /var/log/btmp > btmp.log

Przykład wyniku pierwszego polecenia:

root@darkstar:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.4.0-124 ] [0.0.0.0 ] [2022-09-09T08:50:44] [1] [00053] [~~ ] [runlevel] [~ ] [5.4.0-124 ] [0.0.0.0 ] [2022-09-09T08:50:47] [6] [01632] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [2022-09-09T08:50:47] [7] [2274769] [ts/0] [user1 ] [pts/0 ] [10.26.66.211 ] [10.26.66.21] [2022-10-26T20:40:20] [7] [1523904] [ts/2] [user2 ] [pts/2 ] [tmux(1523904)] [0.0.0.0 ] [2022-10-11T08:33:34] [8] [2208800] [ts/3] [ ] [pts/3 ] [ ] [10.26.66.18] [2022-10-25T15:08:40] [8] [199368] [ts/4] [user3 ] [pts/4 ] [ ] [0.0.0.0 ] [2022-10-25T15:08:40] [7] [851212] [ts/5] [user4 ] [pts/5 ] [10.34.0.82 ] [10.34.0.82 ] [2022-09-27T09:58:06] [8] [852699] [ts/7] [user2 ] [pts/7 ] [ ] [0.0.0.0 ] [2022-10-11T08:30:09] [8] [1316639] [ts/1] [ ] [pts/1 ] [ ] [10.26.66.23] [2022-10-07T08:41:25] [8] [199368] [ts/8] [user3 ] [pts/8 ] [ ] [0.0.0.0 ] [2022-10-25T15:08:40] [8] [199368] [ts/9] [user3 ] [pts/9 ] [ ] [0.0.0.0 ] [2022-10-25T15:08:40] [8] [199368] [s/10] [user4 ] [pts/10] [ ] [0.0.0.0 ] [2022-10-25T15:08:40] [8] [2210372] [s/11] [ ] [pts/11] [ ] [10.26.19.19] [2022-10-25T15:29:19] [7] [1523904] [s/13] [user2 ] [pts/13] [tmux(1523904)] [0.0.0.0 ] [2022-10-25T12:49:27]

Powyższy listing pokazuje takie rzeczy, jak terminal używany do logowania („tty1” / „pts/0”), używana nazwa użytkownika („user1”), używany adres IP („10.26.66.211”) oraz znacznik czasu logowania i wylogowania. Możemy także zobaczyć inne zdarzenia systemowe, takie jak ponowne uruchomienie systemu. Format wyjściowy utmpdump dla wszystkich trzech plików jest identyczny.

Czyszczenie wpisów z logów – metoda usuwania:

Ale co, jeżeli atakujący wykorzysta narzędzie do czyszczenia dziennika? jeżeli uruchomi je przeciwko plikowi utmp to usunie identyfikator przejętego użytkownika nawet, jeżeli ten jest zalogowany w systemie. Możemy to zobaczyć na przykładzie użytkownika malware:

root@darkstar:~# w 20:58:16 up 3 days, 22:56, 3 users, load average: 0.07, 0.09, 0.04 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT agresor pts/0 10.230.161.60 20:49 0.00s 0.42s 0.07s sshd: agresor [priv] malware pts/1 10.220.160.10 20:53 4:27 0.20s 0.20s -bash malware pts/2 10.220.160.10 20:58 4.00s 0.20s 0.20s -bash

Za pomocą programu Linux Log Cleaner usuniemy teraz jego dwa wpisy:

root@darkstar:~# python3 LLC.py -l0 -u malware -f /var/run/utmp \_/ _ \______/ | | | | / _0_0_\ | | | | | | ' ' | | | | | | logs y [-]tamper records: success [-]check it with command: lastb Good Luck :)

Spójrzmy teraz jak wygląda plik /var/run/utmp:

root@stardust:~# w 21:12:06 up 3 days, 23:10, 1 user, load average: 0.09, 0.14, 0.09 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT agresor pts/0 10.230.161.60 20:49 1.00s 0.44s 0.07s sshd: agresor [priv] root@stardust:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.4.0-131 ] [0.0.0.0 ] [2022-10-24T20:02:30] [6] [01363] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [2022-10-24T20:02:48] [1] [00053] [~~ ] [runlevel] [~ ] [5.4.0-131 ] [0.0.0.0 ] [2022-10-24T20:02:51] [7] [02904] [ts/0] [agresor ] [pts/0] [10.230.161.60] [10.230.161.60] [2022-10-24T20:07:30]

Ten sam proces usuwania możemy wykonać tylko dzięki narzędzia utmpdump. Na początek utrudniamy wykrycie jakie polecenie zostało wydane:

root@darkstar:~# unset HISTFILE HISTSAVE HISTMOVE HISTZONE HISTORY HISTLOG USERHST \ REMOTEHOST REMOTEUSER; export HISTSIZE=0

Sprawdzamy aktualny rejestr logowań:

root@darkstar:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:08] [1] [00053] [~~ ] [runlevel] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:10] [6] [00709] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [2022-10-28T19:32:11] [7] [01655] [ts/0] [malware ] [pts/0] [10.220.160.10] [10.220.160.10] [2022-10-28T19:50:13] [7] [01687] [ts/1] [malware ] [pts/1] [10.220.160.10] [10.220.160.10] [2022-10-28T19:50:18]

Wycinamy z danych wyjściowych polecenia utmpdump użytkownika malware:

root@darkstar:~# utmpdump /var/run/utmp | grep -v 'malware' > niewidzialny.txt Utmp dump of /var/run/utmp

Wczytujemy przefiltrowane dane z powrotem do pliku /var/run/utmp dzięki utmpdump:

root@darkstar:~# utmpdump -r /var/run/utmp Utmp undump of /dev/stdin

Sprawdzamy wynik naszych operacji:

root@darkstar:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:08] [1] [00053] [~~ ] [runlevel] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:10] [6] [00709] [tty1] [LOGIN ] [tty1] [ ] [0.0.0.0 ] [2022-10-28T19:32:11]

Wykrywanie czyszczenia wpisów z logów – metodą usuwania:

Jeśli nasz system przestał raportować wydawane polecenia to nieco trudniejsze staje się wykrycie czyszczenia metodą usuwania, ponieważ technika ta powoduje, iż całe wiersze są pomijane w dzienniku poprzez kompleksowe nadpisanie plików *tmp. Wykrycie tego faktu można jednak dokonać patrząc na sygnatury czasowe plików (należy jednak mieć świadomość, iż sygnatury również mogą zostać zmanipulowane). Proces wykrycia zaczynamy od uzyskania informacji o czasie dodania ostatniego wpisu:

root@darkstar:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:08] [1] [00053] [~~ ] [runlevel] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:10] [6] [00709] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [2022-10-28T19:32:11] [7] [00936] [ts/0] [agresor ] [pts/0] [10.230.161.60] [10.230.161.60] [2022-10-28T19:33:31] [7] [00969] [ts/1] [malware ] [pts/1] [10.220.160.10] [10.220.160.10] [2022-10-28T19:35:47]

Sprawdźmy teraz sygnatury czasowe tego pliku:

root@darkstar:~# stat /var/run/utmp File: /var/run/utmp Size: 1920 Blocks: 8 IO Block: 4096 regular file Device: 18h/24d Inode: 1066 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 0/ root) Gid: ( 43/ utmp) Access: 2022-10-28 19:35:47.236772933 +0000 Modify: 2022-10-28 19:35:47.232772925 +0000 Change: 2022-10-28 19:35:47.232772925 +0000 Birth: -

Jeśli teraz porównamy pogrubione znaczniki czasu z obu danych wyjściowych utmpdump i stat to powinny one zawsze pasować, co do sekundowej dokładności. Sprawdźmy teraz jak będą wyglądać sygnatury po dokonaniu edycji. Usuńmy ponownie dane użytkownika malware:

root@darkstar:~# python3 LLC.py -l0 -u malware -f /var/run/utmp \_/ _ \______/ | | | | / _0_0_\ | | | | | | ' ' | | | | | | logs y [-]tamper records: success [-]check it with command: lastb Good Luck :)

Dokonajmy sprawdzenia pliku /var/run/utmp:

root@darkstar:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:08] [1] [00053] [~~ ] [runlevel] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-28T19:32:10] [6] [00709] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [2022-10-28T19:32:11] [7] [00936] [ts/0] [agresor ] [pts/0] [10.230.161.60] [10.230.161.60] [2022-10-28T19:33:31]

Sprawdźmy teraz sygnatury czasowe tego pliku:

root@darkstar:~# stat /var/run/utmp File: /var/run/utmp Size: 1152 Blocks: 8 IO Block: 4096 regular file Device: 18h/24d Inode: 1066 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 0/ root) Gid: ( 43/ utmp) Access: 2022-10-28 19:42:03.070344186 +0000 Modify: 2022-10-28 19:42:03.070344186 +0000 Change: 2022-10-28 19:42:03.070344186 +0000 Birth: -

Widzimy, iż znaczniki czasu: dostępu, modyfikacji i zmiany pliku z polecenia stat są znacznie późniejsze niż ostatni wpis wyciągnięty narzędziem utmpdump. Oznacza to, iż ktoś dokonał modyfikacji pliku w innym czasie niż nastąpiło ostatnie logowanie użytkownika w systemie. Czasami czas dostępu do pliku (Access) może być już zupełnie inny niż pozostałe. Może to być spowodowane flagą montowania systemu plików noatime, która często jest używana do zwiększenia wydajności operacji I/O na dysku.

Czyszczenie wpisów z logów – metoda zerowania:

Starszą metodą od usuwania konkretnych wpisów z plików *tmp było zerowanie ich wartości. Jest ona trywialna do wykonania, ale pozostawia po sobie, co najmniej dwa ślady umożliwiające wykrycie (charakterystyczny wpis i/lub złą datę modyfikacji). Do przeprowadzenia tej metody również istnieją odpowiednie narzędzia, których możemy użyć, aby to zrobić, ale w większości są one przestarzałe. Do wyzerowania dowolnych wpisów możemy użyć edytora heksadecymalnego:

00000770 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 69 04 00 00 70 74 73 2F 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000007A8 74 73 2F 31 61 67 72 65 73 6F 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 39 32 2E 31 36 38 2E 35 36 2E 31 00 00 00 00 00 00 00 00 000007E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000818 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000850 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000888 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000008C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 D5 5E 63 67 82 02 00 C0 A8 38 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000008F8 00 00 00 00 00 00 00 00

Jeśli wyzerujemy teraz wszystkie te wartości wynik polecenia utmpdump będzie miał postać:

root@darkstar:~# utmpdump /var/run/utmp Utmp dump of /var/run/utmp [2] [00000] [~~ ] [reboot ] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-30T19:39:18] [1] [00053] [~~ ] [runlevel] [~ ] [5.15.0-41 ] [0.0.0.0 ] [2022-10-30T19:39:21] [6] [00703] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [2022-10-30T19:39:22] [7] [01093] [ts/0] [agresor ] [pts/0] [192.168.56.1] [192.168.56.1 ] [2022-10-30T19:49:19] [0] [00000] [ ] [ ] [ ] [ ] [0.0.0.0 ] [1970-01-01T00:00:00]

Jeśli przyjrzymy się uważnie to możemy zobaczyć, jak ostatni wpis dziennika wygląda trochę dziwnie. Wartości w każdym polu są zerami, a to nie jest normalne. choćby data pokazuje rok 1970-01-01, co w języku Uniksa oznacza, iż są to również same zera (Unix Epoch). Aby gwałtownie określić, czy nasze logi zostały zmanipulowane dzięki narzędzia do czyszczenia logów metodą zerowania, możemy użyć tych prostych poleceń grep:

utmpdump /var/run/utmp | grep "\[0\].*1970-01-01" utmpdump /var/log/wtmp | grep "\[0\].*1970-01-01" utmpdump /var/log/btmp | grep "\[0\].*1970-01-01"

Te polecenia przeszukują logi logowań w poszukiwaniu wpisów, które wydają się być same zerami. To nie jest normalne zachowanie w systemie Linux i stanowi świecącą czerwoną lampkę. W powyższych przykładach został użyty tylko plik /var/run/utmp, ale techniki te można użyć dla wszystkich trzech opisanych artefaktów.

Bonus („blokowanie” poleceń 'who’ oraz 'w’):

Jakie jest najczęściej wykorzystywane polecenie przez administratorów do wyświetlenia zalogowanych użytkowników na systemie? Myślę, iż większość czytelników wskaże na polecenie who lub w:

root@darkstar:~# w 17:48:40 up 12 min, 2 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT agresor pts/0 192.168.56.1 17:40 8:24 0.23s 0.03s sshd: agresor [priv] agresor pts/1 192.168.56.1 17:40 0.00s 0.02s 0.22s sudo su - root@darkstar:~# who agresor pts/0 2022-10-26 17:40 (192.168.56.1) agresor pts/1 2022-10-26 17:40 (192.168.56.1)

Jeśli sprawdzimy z jakich plików korzystają te polecenia odkryjemy, iż nie tylko używany jest tylko plik /var/run/utmp, ale także /var/run/utmpx tylko nie jest on znajdowany w szukanej ścieżce:

root@darkstar:~# strace w 2>&1 | grep '/var/run/utmp' read(4, "grep\0--color=auto\0/var/run/utmp\0", 2047) = 32 access("/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 4 access("/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 5 root@darkstar:~# strace who 2>&1 | grep '/var/run/utmp' access("/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3

Pliki utmpx i wtmpx to rozszerzenia oryginalnych utmp i wtmp, pochodzących od Sun Microsystems. Utmpx jest określony w POSIX. Pliki utmp, wtmp, i btmp nigdy nie były częścią żadnego oficjalnego standardu Unix, takiego jak Single UNIX Specification, podczas gdy utmpx i odpowiadające im interfejsy API są jego częścią. Chociaż niektóre systemy tworzą różne nowsze pliki dla wariantów utmpx i mają przestarzałe / nieaktualne poprzednie formaty to Linux na przykład używa struktury utmpx w miejscu starszej struktury plików. jeżeli teraz stworzymy kopię pliku utmp pod nazwą utmpx i zablokujemy do niego zapis – to polecenia w oraz who będą pokazywały cały czas ten sam stan zalogowanych użytkowników – jak na zapętlonym monitoringu z filmów akcji:

# Kopiujemy plik utmp na inny system plików niż tmpfs: cp /var/run/utmp /boot/utmpx # Linkujemy plik na nową lokalizację: ln -s /boot/utmpx /var/run/utmpx # Blokujemy zapis do pliku utmpx: chattr +i /boot/utmpx

Jeśli teraz sprawdzimy kto jest zalogowany w systemie zawsze otrzymamy wynik:

root@darkstar:~# w 18:53:17 up 9 min, 2 users, load average: 0.00, 0.02, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT agresor pts/0 192.168.56.1 18:49 4:12 0.02s 0.02s sshd: agresor [priv] agresor pts/1 192.168.56.1 18:49 3.00s 0.03s 0.01s sudo su - root@darkstar:~# who agresor pts/0 2022-10-26 18:49 (192.168.56.1) agresor pts/1 2022-10-26 18:49 (192.168.56.1)

Oprócz daty, uptime i load average nic innego nie ulegnie zmianie, a w rzeczywistości sesji użytkownika agresor jest znacznie więcej:

root@darkstar:~# ps aw -u agresor PID TTY STAT TIME COMMAND 714 tty1 Ss+ 0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux 851 ? Ss 0:00 /lib/systemd/systemd --user 852 ? S 0:00 (sd-pam) 1024 ? S 0:00 sshd: agresor@pts/0 1025 pts/0 Ss 0:00 -bash 1034 pts/0 S+ 0:00 sudo su - 1035 pts/1 Ss 0:00 sudo su - 1036 pts/1 S 0:00 su - 1037 pts/1 S+ 0:00 -bash 1080 ? S 0:00 sshd: agresor@pts/2 1081 pts/2 Ss 0:00 -bash 1090 pts/2 R+ 0:00 sudo su - 1091 pts/3 Ss 0:00 sudo su - 1092 pts/3 S 0:00 su - 1093 pts/3 S 0:00 -bash 1130 ? S 0:00 sshd: agresor@pts/4 1131 pts/4 Ss 0:00 -bash 1140 pts/4 S+ 0:00 sudo su - 1141 pts/5 Ss 0:00 sudo su - 1142 pts/5 S 0:00 su - 1143 pts/5 S+ 0:00 -bash

Dzieje się tak, ponieważ polecenia w oraz who korzystają z pierwszego napotkanego źródła danych, które właśnie „zamroziliśmy”:

root@darkstar:~# strace w 2>&1 | grep '/var/run/utmp' read(4, "grep\0--color=auto\0/var/run/utmp\0", 2047) = 32 access("/var/run/utmpx", F_OK) = 0 openat(AT_FDCWD, "/var/run/utmpx", O_RDONLY|O_CLOEXEC) = 4 access("/var/run/utmpx", F_OK) = 0 openat(AT_FDCWD, "/var/run/utmpx", O_RDONLY|O_CLOEXEC) = 5 root@darkstar:~# strace who 2>&1 | grep '/var/run/utmp' access("/var/run/utmpx", F_OK) = 0 openat(AT_FDCWD, "/var/run/utmpx", O_RDONLY|O_CLOEXEC) = 3

W ten sposób możemy pozostać niezauważeni dla tych poleceń bez konieczności modyfikacji oryginalnego pliku utmp.

Więcej informacji: utmp, Using Linux utmpdump for Forensics and Detecting Log File Tampering, Detecting Linux Anti-Forensics Log Tampering, utmpx, Learning on who, utmp

Idź do oryginalnego materiału