NFsec Logo

Wyłączenie ładowania niepodpisanych modułów

11/06/2025 (2 tygodnie temu) w Bezpieczeństwo Brak komentarzy.  (artykuł nr 927, ilość słów: 669)

M

oduły dostarczane przez dystrybucyjne jądra pochodzą z ich kodu źródłowego. Powstają one podczas procesu kompilacji jądra, a narzędzia towarzyszące przy tej operacji tworzą parę autowygenerowanych kluczy (prywatny / publiczny) i podpisują każdy moduł powstający z drzewa kodu źródłowego jądra (używając klucza prywatnego). Klucz publiczny jest zapisywany w samym jądrze systemu. Gdy moduł dostarczony z jądrem jest ładowany w systemie, klucz publiczny może zostać użyty do sprawdzenia, czy moduł pozostał niezmieniony i pochodzi z pierwotnego drzewa kodu źródłowego. Podczas uruchamiania systemu możemy poinstruować jądro, aby zawsze weryfikowało moduły i raportowało wszelkie niepowodzenia ładowania modułów „spoza drzewa” do logów, ponieważ gdy „wymusimy” obsługę tylko podpisanych modułów jądra – system Linux będzie ładować tylko moduły podpisane cyfrowo wcześniej autowygenerowanym kluczem.

Umożliwia to szybkie i proste wzmocnienie systemu (oraz uzupełnienie wyłączenia ładowania dodatkowych modułów) poprzez uniemożliwienie ładowania niepodpisanych modułów lub modułów podpisanych niewłaściwym kluczem. W samym na eliminację złośliwych modułów, które są powszechną metodą do instalacji rootkitów w systemie Linux. Weryfikacja podpisanych modułów jest funkcją jądra, więc musi być włączona poprzez jego konfigurację. Niezbędne opcje możemy znaleźć w menu przy kompilacji:

[*] Enable loadable module support  --->
  [*] Module signature verification
  [ ]   Require modules to be validly signed
  [*]   Automatically sign all modules
      Which hash algorithm should modules be signed with? (Sign modules with SHA-512) --->

co również ma swoje odzwierciedlenie w zapisanej konfiguracji jądra:

 
root@darkstar:~# grep CONFIG_MODULE_SIG /boot/config-`uname -r`
CONFIG_MODULE_SIG_FORMAT=y
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_FORCE is not set
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_SHA512=y
CONFIG_MODULE_SIG_HASH="sha512"
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set

Opcja „Module signature verification” (CONFIG_MODULE_SIG) włącza weryfikację podpisu modułów w jądrze Linux. Obsługuje ona dwa podejścia do obsługi podpisanych modułów: tryb zezwalający i rygorystyczny. Domyślnie używane jest podejście dopuszczające, co oznacza, że moduły jądra Linux mogą mieć lub nie mieć podpisu odpowiednim kluczem. W przypadku wybrania podejścia rygorystycznego, poprawny podpis musi być obecny dla modułu. W powyższym przykładzie tryb rygorystyczny nie jest wybrany: „Require modules to be validly signed” (CONFIG_MODULE_SIG_FORCE). Ale nic straconego, ponieważ innym sposobem jego włączenia jest ustawienie opcji rozruchowej jądra: module.sig_enforce=1. W systemie Ubuntu wystarczy edytować plik: /etc/default/grub i w sekcji GRUB_CMDLINE_LINUX dodać wspomnianą opcję rozruchową:

root@darkstar:~# grep GRUB_CMDLINE_LINUX /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX="module.sig_enforce=1"

Następnie aktualizujemy ustawienia GRand Unified Bootloader:

root@darkstar:~# update-grub
Sourcing file `/etc/default/grub'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.8.0-60
Found initrd image: /boot/initrd.img-6.8.0-60
Adding boot menu entry for UEFI Firmware Settings ...
done

Możemy sprawdzić, czy przy następnym restarcie systemu opacja rozruchowa zostanie przekazana do jądra:

root@darkstar:~# grep module.sig_enforce /boot/grub/grub.cfg
linux /boot/vmlinuz-6.8.0-60 root=UUID=1bd02967 ro module.sig_enforce=1 console=ttyS0

Po restarcie systemu możemy spróbować załadować „obcy” moduł do systemu:

root@darkstar:~# make all
make -C /lib/modules/6.8.0-60/build M=/root modules
make[1]: Entering directory '/usr/src/linux-headers-6.8.0-60'
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/nfsec_rootkit.o
  MODPOST /root/Module.symvers
  CC [M]  /root/nfsec_rootkit.mod.o
  LD [M]  /root/nfsec_rootkit.ko
  BTF [M] /root/nfsec_rootkit.ko
Skipping BTF generation for /root/nfsec_rootkit.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.8.0-60'

root@darkstar:~# insmod nfsec_rootkit.ko
insmod: ERROR: could not insert module nfsec_rootkit.ko: Key was rejected by service

root@darkstar:~# dmesg -T | grep 'unsigned module'
[Wed Jun 11 20:53:44 2025] Loading of unsigned module is rejected

Gdzie inne moduły są załadowane i podpisane:

root@darkstar:~# modprobe x_tables
root@darkstar:~# modinfo x_tables | grep ^sig
sig_id:         PKCS#7
signer:         Build time autogenerated kernel key
sig_key:        6D:97:F7:E0:E3:5E:DD:23:6A:0F:B7:E7:57:F1:51:88:FD:C7:1A:3A
sig_hashalgo:   sha512
signature:      8A:6F:6F:31:72:E5:22:7D:75:46:B9:DD:C4:0A:E9:B2:A9:C4:8D:71:

Należy mieć na uwadze, że tego typu „szybkie” rozwiązanie powinno być stosowane na systemach, które nie przewidują ładowania dodatkowych modułów pochodzących spoza oficjalnego jądra systemu dostarczonego przez dystrybucję. Wymuszenie rygorystycznego trybu powoduje użycie autowygenerowanych kluczy, do których nie mamy już dostępu. Dlatego nie mamy możliwości wykorzystania ich do podpisania zewnętrznych, zaufanych modułów. W tym celu należy stworzyć i wykorzystać własne klucze kryptograficzne.

Więcej informacji: Signed kernel module support, Signed kernel modules, Kernel module signing facility, How to Use Signed Kernel Modules

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.