NFsec Logo

Linux rootkits – wykrywanie ukrytych plików i katalogów

08/08/2025 (2 dni temu) w Bezpieczeństwo Brak komentarzy.  (artykuł nr 930, ilość słów: 1140)

O

programownie typu rootkit stanowi klasę złośliwego oprogramowania (ang. malware), które zostało zaprojektowane w celu zapewnienia ukrytego, trwałego i uprzywilejowanego dostępu do skompromitowanego systemu. Jako post-eksploatacyjne narzędzie (stanowiące końcowy wektor ataku) zazwyczaj uzbrojone jest w funkcje umożliwiające: persystencję działania; eksfiltrację danych; eskalację uprawnień; ukrywanie swoich złośliwych komponentów pod postacią procesów, połączeń sieciowych, a przede wszystkim plików i katalogów. Ukrywanie plików i katalogów odbywa się poprzez modyfikację funkcji jądra systemu odpowiedzialnych za wyświetlanie listy plików i informacji o nich. Zamiast tworzyć i usuwać pliki (co byłoby łatwe do wykrycia) rootkit zmienia sposób, w jaki system „widzi” i raportuje posiadane pliki.

Działając na poziomie jądra systemu (ang. kernel mode) jako ładowalne moduły (ang. LKMLoadable Kernel Module) wykorzystują technikę przechwytywania wywołań systemowych (ang. system calls), z których korzystają standardowe polecenia systemu Linux. Pozwala to na modyfikację przepływających przez nie danych, aby przed zwróceniem wyników przefiltrowanie i ukrycie plików o określonych nazwach. Poniżej zostanie zaprezentowany przykład działania Diamorphine, który przechwytuje wywołania systemowe takie jak: readdir() oraz getdents64(), aby oszukać np. polecenie ls i ukryć pliki lub katalogi zaczynający się od frazy: diamorphine_secret:

root@darkstar:~# git clone https://github.com/m0nad/Diamorphine
Cloning into 'Diamorphine'...
remote: Enumerating objects: 144, done.
remote: Counting objects: 100% (68/68), done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 144 (delta 54), reused 44 (delta 42), pack-reused 76 (from 1)
Receiving objects: 100% (144/144), 33.13 KiB | 892.00 KiB/s, done.
Resolving deltas: 100% (78/78), done.

root@darkstar:~/Diamorphine# make
make -C /lib/modules/4.15.0-213-generic/build M=/root/Diamorphine modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-213-generic'
  CC [M]  /root/Diamorphine/diamorphine.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/Diamorphine/diamorphine.mod.o
  LD [M]  /root/Diamorphine/diamorphine.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-213-generic'

root@darkstar:~/Diamorphine# grep MAGIC diamorphine.h
#define MAGIC_PREFIX "diamorphine_secret"

Tworząc teraz dwa katalogi o odpowiednich nazwach i załadowaniu skompilowanego modułu – jeden z katalogów powinien zniknąć nam z aktualnego wykazu systemu plików:

root@darkstar:~/Diamorphine# cd /usr/games
root@darkstar:/usr/games# mkdir diamorphine_secret
root@darkstar:/usr/games# mkdir malicious_secret
root@darkstar:/usr/games# ls -al
total 16
drwxr-xr-x  4 root root 4096 Aug  5 17:25 .
drwxr-xr-x 10 root root 4096 Aug  5 17:04 ..
drwxr-xr-x  2 root root 4096 Aug  5 17:25 diamorphine_secret
drwxr-xr-x  2 root root 4096 Aug  5 17:25 malicious_secret

root@darkstar:/usr/games# insmod /root/Diamorphine/diamorphine.ko
root@darkstar:/usr/games# ls -al
total 12
drwxr-xr-x  4 root root 4096 Aug  5 17:25 .
drwxr-xr-x 10 root root 4096 Aug  5 17:04 ..
drwxr-xr-x  2 root root 4096 Aug  5 17:25 malicious_secret

Sprawdźmy ile katalogów „widzi” polecenie ls:

root@darkstar:/usr/games# ls -d . .. */ | wc -l
3

Zapytajmy teraz o to samo, ale korzystając z wywołania systemowego stat, które nie jest przechwytywane przez szkodliwy moduł:

root@darkstar:/usr/games# stat -c %h .
4

3 != 4, co stanowi potwierdzenie, że jeden z katalogów jest ukrywany. Nie zawsze jednak mamy możliwość wykorzystania polecenia stat w celu zdemaskowania ukrytego katalogu. Bardziej zaawansowane narzędzia rootkit (np. KoviD), mogą również przechwytywać jego wywołania systemowe „oślepiając” ten sposób detekcji:

root@darkstar:~# apt-get install uuid-runtime
root@darkstar:~# git clone https://github.com/carloslack/KoviD
Cloning into 'KoviD'...
remote: Enumerating objects: 2290, done.
remote: Counting objects: 100% (1053/1053), done.
remote: Compressing objects: 100% (427/427), done.
remote: Total 2290 (delta 720), reused 635 (delta 624), pack-reused 1237 (from 2)
Receiving objects: 100% (2290/2290), 27.58 MiB | 3.79 MiB/s, done.
Resolving deltas: 100% (1485/1485), done.

root@darkstar:~# cd KoviD/
root@darkstar:~/KoviD# make PROCNAME="agr3s0r"
make  -C  /lib/modules/6.8.0-71-generic/build M=/root/KoviD modules
make[1]: Entering directory '/usr/src/linux-headers-6.8.0-71-generic'
warning: the compiler differs from the one used to build the kernel
  The kernel was built by: x86_64-linux-gnu-gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
  You are using:           gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
  CC [M]  /root/KoviD/src/kovid.o
  CC [M]  /root/KoviD/src/pid.o
  CC [M]  /root/KoviD/src/fs.o
  CC [M]  /root/KoviD/src/sys.o
  CC [M]  /root/KoviD/src/sock.o
  CC [M]  /root/KoviD/src/util.o
  CC [M]  /root/KoviD/src/vm.o
  CC [M]  /root/KoviD/src/crypto.o
  CC [M]  /root/KoviD/src/tty.o
  LD [M]  /root/KoviD/kovid.o
  MODPOST /root/KoviD/Module.symvers
  CC [M]  /root/KoviD/kovid.mod.o
  LD [M]  /root/KoviD/kovid.ko
  BTF [M] /root/KoviD/kovid.ko
Skipping BTF generation for /root/KoviD/kovid.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.8.0-71-generic'
Build complete.
Backdoor KEY: 633dde70d0ad2534
LKM unhide KEY: a42f54847276a258
UI: /proc/agr3s0r
/proc/agr3s0r timeout: 1200
Object name: kovid.ko
Build type: DEBUG

Ukryjmy ponownie katalogi i sprawdźmy, czy będziemy w stanie je wykryć w/w metodą:

root@darkstar:~/KoviD# insmod kovid.ko
root@darkstar:~/KoviD# kill -CONT 31337
root@darkstar:~/KoviD# dmesg -T
[Mon Aug  4 18:03:40 2025] /proc/agr3s0r loaded, timeout: 1200s
root@darkstar:~/KoviD# cd /usr/games
root@darkstar:/usr/games# mkdir secret_dir normal_dir
root@darkstar:/usr/games# touch secret_file.txt normal_file.txt
root@darkstar:/usr/games# ls -al
total 16
drwxr-xr-x  4 root root 4096 Aug  4 18:19 .
drwxr-xr-x 10 root root 4096 Feb 16 20:51 ..
drwxr-xr-x  2 root root 4096 Aug  4 18:19 normal_dir
-rw-r--r--  1 root root    0 Aug  4 18:19 normal_file.txt
drwxr-xr-x  2 root root 4096 Aug  4 18:19 secret_dir
-rw-r--r--  1 root root    0 Aug  4 18:19 secret_file.txt

root@darkstar:/usr/games# echo hide-file=secret_file.txt >/proc/agr3s0r
root@darkstar:/usr/games# echo hide-directory=secret_dir >/proc/agr3s0r
root@darkstar:/usr/games# ls -al
total 12
drwxr-xr-x  3 root root 4096 Aug  4 18:19 .
drwxr-xr-x 10 root root 4096 Feb 16 20:51 ..
drwxr-xr-x  2 root root 4096 Aug  4 18:19 normal_dir
-rw-r--r--  1 root root    0 Aug  4 18:19 normal_file.txt

root@darkstar:/usr/games# ls -d . .. */ | wc -l
3
root@darkstar:/usr/games# stat -c %h .
3

3 = 3. Jeśli jednak nasz serwer używa systemu plików, który jest oparty o EXT(2|3|4) to możemy użyć programu debugfs. Nie jest on typowym programem działającym w przestrzeni użytkownika, ale interaktywnym debuggerem działającym na niskim poziomie, który ma dostęp do surowych danych na urządzeniu blokowym. Omijając standardowy dostęp do systemu plików z poziomu jądra może oddziaływać bezpośrednio z urządzeniem odkrywając jego karty. Poniżej znajduje się prosty skrypt, który może nam pomóc w sprawdzeniu konkretnych ścieżek:

#!/bin/bash

if [ "$#" -ne 1 ]; then
    echo "Usage: $0 "
    exit 1
fi

DIR="$1"
DISK=$(findmnt -n --output SOURCE --target "$DIR")

if [ -z "$DISK" ]; then
    echo "Error: Can't find filesystem for directory: $DIR"
    exit 1
fi

debugfs -R "ls -l $DIR" "$DISK" | cat

root@darkstar:~# ./unhide.sh /usr/games
debugfs 1.47.0 (5-Feb-2023)
 532258   40755 (2)      0      0    4096  8-Aug-2025 19:48 .
 524297   40755 (2)      0      0    4096 16-Feb-2025 20:51 ..
 683116   40755 (2)      0      0    4096  4-Aug-2025 19:09 secret_dir
 683124   40755 (2)      0      0    4096  4-Aug-2025 18:19 normal_dir
 525259  100644 (1)      0      0       0  4-Aug-2025 18:19 secret_file.txt
 525260  100644 (1)      0      0       0  4-Aug-2025 18:19 normal_file.txt

Więcej informacji: Ukrywanie procesów za pomocą ld.so.preload, Detecting Linux Stealth Rootkits with Directory Link Errors

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

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

Brak nowszych postów

Komentowanie tego wpisu jest zablokowane.