NFsec Logo

Wykrywanie pozorowania procesów jądra za pomocą linii poleceń

06/06/2020 w Bezpieczeństwo Brak komentarzy.  (artykuł nr 737, ilość słów: 2947)

W

nawiązaniu do “Ściągawki z informatyki śledczej w wykrywaniu włamań za pomocą linii poleceń Linuksa” dzisiaj zajmiemy się maskowaniem procesów, które czasem jest wykorzystywane przez złośliwe oprogramowanie. Z pomocą ponownie przyjdzie nam magia linii poleceń Linuksa, która umożliwi nam zdemaskowanie prawdziwego intruza w systemie. Na początku odpowiedzmy sobie na pytanie: czym jest maskarada procesów jądra Linux? Otóż w systemie Linux jądro posiada wiele własnych wątków utworzonych w celu ułatwienia wykonywania zadań systemowych. Wątki te mogą służyć do planowania obsługi zadań (ang. scheduling), operacji I/O na urządzeniach blokowych, wykonać transakcje księgowania dla systemów plików, okresowej synchronizacji zmodyfikowanych stron pamięci itd.

Jeśli użyjemy standardowego polecenia służącego do wyświetlania procesów, takiego jak: ps auxw, wątki te pojawią się w formie opakowanej w [nawiasy kwadratowe]. Zwykłe procesy systemowe zwykle nie pojawiają się w tej formie. Nawiasy kwadratowe oznaczają, że proces nie ma argumentów wiersza poleceń, co zwykle oznacza, że został uruchomiony jako wątek. Na przykład poniższa lista pokazuje wątki jądra w porównaniu do normalnych procesów:

root@darkstar:~# ps xuaw
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
# WĄTKI JĄDRA
root       145  0.0  0.0      0     0 ?        S    May28   0:00 [watchdogd]
root       146  0.0  0.0      0     0 ?        S    May28   0:00 [kswapd0]
root       147  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/u9:0]
root       148  0.0  0.0      0     0 ?        S    May28   0:00 [ecryptfs-kthrea]
# NORMALNE PROCESY
root       777  0.0  0.1  31920  3236 ?        Ss   May28   0:01 /usr/sbin/cron -f
root       383  0.0  0.0  97704  1804 ?        Ss   May28   0:00 /sbin/lvmetad -f
root      1049  0.0  0.3  72296  6360 ?        Ss   May28   0:00 /usr/sbin/sshd -D

Złośliwe oprogramowanie w systemie Linux wykorzystuje różne techniki, aby ukryć się przed wykryciem. Jedną z metod, których używa to próba podszywania się pod wątek jądra – poprzez wyświetlanie procesu w otoczeniu [nawiasów] wokół jego nazwy na liście procesów. W ten sposób administratorzy mogą łatwo przeoczyć złośliwy proces. Jeśli spojrzysz teraz na poniższy wykaz procesów to czy jesteś w stanie jednoznacznie wskazać, który ukrywa się jako wątek jądra?

root         2  0.0  0.0      0     0 ?        S    May28   0:00 [kthreadd]
root         6  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/0:0H-kb]
root         9  0.0  0.0      0     0 ?        S    May28   0:07 [ksoftirqd/0]
root        18  0.0  0.0      0     0 ?        S    May28   0:07 [ksoftirqd/1]
root        20  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/1:0H-kb]
root        24  0.0  0.0      0     0 ?        S    May28   0:05 [ksoftirqd/2]
root        26  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/2:0H-kb]
root        30  0.0  0.0      0     0 ?        S    May28   0:07 [ksoftirqd/3]
root        32  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/3:0H-kb]
root        33  0.0  0.0      0     0 ?        S    May28   0:00 [kdevtmpfs]
root        36  0.0  0.0      0     0 ?        S    May28   0:00 [kauditd]
root        37  0.0  0.0      0     0 ?        S    May28   0:01 [khungtaskd]
root        40  0.0  0.0      0     0 ?        S    May28   0:00 [kcompactd0]
root        41  0.0  0.0      0     0 ?        SN   May28   0:00 [ksmd]
root        42  0.0  0.0      0     0 ?        SN   May28   0:00 [khugepaged]
root       136  0.0  0.0      0     0 ?        I<   May28   0:00 [kintegrityd]
root       137  0.0  0.0      0     0 ?        I<   May28   0:00 [kblockd]
root       146  0.0  0.0      0     0 ?        S    May28   0:00 [kswapd0]
root       147  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/u9:0]
root       151  0.0  0.0      0     0 ?        I<   May28   0:00 [kthrotld]
root       165  0.0  0.0      0     0 ?        I<   May28   0:00 [kstrp]
root     23438  0.0  0.0   8068   812 ?        S    20:45   0:00 [kworkerd]
root       254  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/3:1H-kb]
root       256  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/0:1H-kb]
root       304  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/1:1H-kb]
root       314  0.0  0.0      0     0 ?        I<   May28   0:00 [kworker/2:1H-kb]
root     10835  0.0  0.0      0     0 ?        I    11:12   0:09 [kworker/0:2-eve]
root     12935  0.0  0.0      0     0 ?        I    13:57   0:06 [kworker/3:1-eve]
root     13205  0.0  0.0      0     0 ?        I    14:02   0:10 [kworker/1:2-eve]
root     13385  0.0  0.0      0     0 ?        I    14:31   0:00 [kworker/1:1-eve]
root     13490  0.0  0.0      0     0 ?        I    14:40   0:00 [kworker/0:1-eve]
root     13952  0.0  0.0      0     0 ?        I    15:30   0:05 [kworker/2:1-eve]
root     14536  0.0  0.0      0     0 ?        I    18:01   0:00 [kworker/u8:1-ev]
root     14708  0.0  0.0      0     0 ?        I    18:38   0:00 [kworker/3:2-eve]
root     23219  0.0  0.0      0     0 ?        I    20:12   0:00 [kworker/u8:2-ev]
root     23298  0.0  0.0      0     0 ?        I    20:27   0:00 [kworker/u8:0-ev]
root     23364  0.0  0.0      0     0 ?        I    20:44   0:00 [kworker/u8:3-ev]

Teraz, gdy wiesz już, jak wygląda jedna z metod maskowania wątków jądra Linux przygotujmy test, abyś mógł się dowiedzieć, jak go znaleźć za pomocą śledzctwa z poziomu linii poleceń. W naszej symulacji użyjemy polecenia sleep, ponieważ nie spowoduje ono żadnych problemów w systemie:

export PATH=.:$PATH
cp /bin/sleep /tmp/[kworkerd]
cd /tmp
"[kworkerd]" 3600 &

Osobliwe eksportowanie ścieżki dostępu (export PATH=.:$PATH) powoduje, że możemy wykonać plik w katalogu lokalnym bez konieczności umieszczenia przed nim frazy: "./". To sprawia, że tak uruchomiony proces wygląda bardziej “naturalnie”. Kolejnym krokiem jest skopiowanie polecenia sleep do katalogu /tmp i uruchomienie go pod fałszywą nazwą [kworked]. Jako argument wpisujemy 3600 sekund, aby proces zakończył się po godzinie działania testów. Spójrzmy teraz jak wygląda proces [kworkerd], gdy wydamy polecenie ps:

root@darkstar:~# ps auxw | grep '\[k'
# PRAWDZIWY WĄTEK JĄDRA
root     23416  0.0  0.0      0     0 ?        I    20:52   0:00 [kworker/u8:1-ev]
# FAŁSZYWY PROCES
root     23438  0.0  0.0   8068   740 pts/0    S    20:54   0:00 [kworkerd] 3600

Przeprowadźmy teraz wykrywanie zamaskowanych procesów jądra za pomocą map procesów. Metoda ta polega na sprawdzeniu, czy dany proces zawiera wpisy w /proc/$PID/map. W tym miejscu utrzymywana jest lista aktualnie zmapowanych regionów pamięci i uprawnienia dostępu do nich. Dla prawdziwych wątków jądra mapy powinny być puste. Jeśli spojrzymy na tę lokalizację w poszukiwaniu procesu o nazwie w [nawiasach] kwadratowych, ale pokaże on jakiekolwiek wpisy – oznacza to, że nie jest to prawdziwy wątek jądra. Prostym poleceniem, którego należy użyć to: cat /proc/23438/maps, gdzie liczba 23438 jest identyfikatorem procesu [kworkerd], który wygląda podejrzanie:

root@darkstar:~# cat /proc/23438/maps
557186324000-55718632b000 r-xp 00000000 08:02 131850      /tmp/[kworkerd]
55718652b000-55718652c000 r--p 00007000 08:02 131850      /tmp/[kworkerd]
55718652c000-55718652d000 rw-p 00008000 08:02 131850      /tmp/[kworkerd]
5571882f8000-557188319000 rw-p 00000000 00:00 0           [heap]
7fc55c737000-7fc55caac000 r--p 00000000 08:05 393301      /usr/lib/locale/locale-archive
7fc55caac000-7fc55cc93000 r-xp 00000000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55cc93000-7fc55ce93000 ---p 001e7000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55ce93000-7fc55ce97000 r--p 001e7000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55ce97000-7fc55ce99000 rw-p 001eb000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55ce99000-7fc55ce9d000 rw-p 00000000 00:00 0
7fc55ce9d000-7fc55cec4000 r-xp 00000000 08:02 23          /lib/x86_64-linux/ld-2.27.so
7fc55d0b7000-7fc55d0b9000 rw-p 00000000 00:00 0
7fc55d0c4000-7fc55d0c5000 r--p 00027000 08:02 23          /lib/x86_64-linux/ld-2.27.so
7fc55d0c5000-7fc55d0c6000 rw-p 00028000 08:02 23          /lib/x86_64-linux/ld-2.27.so
7fc55d0c6000-7fc55d0c7000 rw-p 00000000 00:00 0
7fffaa2f0000-7fffaa311000 rw-p 00000000 00:00 0           [stack]
7fffaa38c000-7fffaa38f000 r--p 00000000 00:00 0           [vvar]
7fffaa38f000-7fffaa390000 r-xp 00000000 00:00 0           [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0   [vsyscall]

Jeśli chcemy szybko przejrzeć wszystkie systemowe identyfikatory $PID i zobaczyć, które z nich są nazwane w nawiasach, ale mają pliki map – możemy zastosować polecenie:

root@darkstar:~# ps auxw | awk '{print $11,$2}' | grep ^\\[ | awk '{print $2}' \
| xargs -I % sh -c 'echo PID: %; cat /proc/%/maps' 2> /dev/null
PID: 10835
PID: 12935
PID: 13205
PID: 13385
PID: 13952
PID: 14708
PID: 23589
PID: 23609
PID: 23630
PID: 23438
557186324000-55718632b000 r-xp 00000000 08:02 131850      /tmp/[kworkerd]
55718652b000-55718652c000 r--p 00007000 08:02 131850      /tmp/[kworkerd]
55718652c000-55718652d000 rw-p 00008000 08:02 131850      /tmp/[kworkerd]
5571882f8000-557188319000 rw-p 00000000 00:00 0           [heap]
7fc55c737000-7fc55caac000 r--p 00000000 08:05 393301      /usr/lib/locale/locale-archive
7fc55caac000-7fc55cc93000 r-xp 00000000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55cc93000-7fc55ce93000 ---p 001e7000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55ce93000-7fc55ce97000 r--p 001e7000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55ce97000-7fc55ce99000 rw-p 001eb000 08:02 32          /lib/x86_64-linux/libc-2.27.so
7fc55ce99000-7fc55ce9d000 rw-p 00000000 00:00 0
7fc55ce9d000-7fc55cec4000 r-xp 00000000 08:02 23          /lib/x86_64-linux/ld-2.27.so
7fc55d0b7000-7fc55d0b9000 rw-p 00000000 00:00 0
7fc55d0c4000-7fc55d0c5000 r--p 00027000 08:02 23          /lib/x86_64-linux/ld-2.27.so
7fc55d0c5000-7fc55d0c6000 rw-p 00028000 08:02 23          /lib/x86_64-linux/ld-2.27.so
7fc55d0c6000-7fc55d0c7000 rw-p 00000000 00:00 0
7fffaa2f0000-7fffaa311000 rw-p 00000000 00:00 0           [stack]
7fffaa38c000-7fffaa38f000 r--p 00000000 00:00 0           [vvar]
7fffaa38f000-7fffaa390000 r-xp 00000000 00:00 0           [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0   [vsyscall]
PID: 23873
PID: 29254

Jeśli na liście zobaczymy wpisy w plikach map, gdzie plik binarny zawiera linki do siebie lub bibliotek, których używa – powinniśmy zbadać te przypadki – szczególnie, gdy widzimy podejrzane biblioteki, odniesienia do ukrytych katalogów itp. Na przykład ściezka /tmp/[kworkerd] jest bardzo podejrzanym procesem wartym zbadania. Innym sposobem na zdemaskowanie procesów udających wątki jest sprawdzenie, czy nie posiadają one plików binarnych dołączonych do uruchomionego procesu (/proc/$PID/exe):

root@darkstar:~# ps auxww | awk '{print $11,$2}' | grep ^\\[ | awk '{print $2}' \
| xargs -I % sh -c 'echo PID: %; sha1sum /proc/%/exe' 2> /dev/null
PID: 10835
PID: 12935
PID: 13205
PID: 13385
PID: 13952
PID: 23609
PID: 23630
PID: 23873
PID: 24533
PID: 24624
PID: 24663
PID: 23438
bebcce23072c4d831ce8e2822a0858d6aa813067  /proc/23438/exe
PID: 25080

W przypadku, gdy polecenie zwórci nam skrót, to jest to normalny proces, który próbuje się ukryć i nie jest wątkiem jądra. Prawdziwe wątki jądra nie będą miały linku do pliku binarnego, który je uruchomił. Plik taki możemy szybko skopiować do innej lokalizacji i wykonać jego analizę na specjalnym, wyizolowanym systemie:

cp /proc/23438/exe /mnt/offline/podejrzany_bin

Wartość jego skrótu możemy użyć do sprawdzenia baz danych znanego złośliwego oprogramowania w celu możliwej identyfikacji.

Więcej informacji: Detecting Linux kernel process masquerading with command line forensics

Kategorie K a t e g o r i e : Bezpieczeństwo

Tagi T a g i : , , , , , , ,

Komentowanie tego wpisu jest zablokowane.