Today I Learned - kernel.modules_disabled
Today I Learned - kernel.modules_disabled
https://dfir.ch/posts/today_i_learned_lkm_kernel.modules_disabled/
10 Jul 2024 Table of Contents
Introduction
Hello, DFIR Kernel Module
Hardening
Conclusion
Introduction
The kernel.modules_disabled parameter is a security feature in the Linux kernel that prevents the loading and unloading of kernel modules. This setting is particularly useful for hardening a system against certain types of attacks, such as attempts to load malicious kernel modules (think rootkits) or manipulate the system at a low level. Mandiant recently published a blog post where they found, among other toolings used by the attackers, REPTILE. REPTILE is an open-source Linux rootkit, implemented as a loadable kernel module (LKM), that provides backdoor access to a system. Source: Cloaked and Covert: Uncovering UNC3886 Espionage Operations
By default, this setting is turned off:
sysctl -a | grep modules
kernel.modules_disabled = 0
Hello, DFIR Kernel Module
We will create a simple kernel module to showcase the kernel feature modules_disabled in action. We saved the code below under the name dfir.c in our home directory. The module is as simple as it can get: When the module is loaded, the string “Hello, DFIR!” will be logged inside the kernel’s message buffer. Subsequently, when the module exists, the string “Goodbye, DFIR!” will be logged.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h>
// Called when the module is loaded static int __init dfir_init(void) { printk(KERN_INFO “Hello, DFIR!\n”); return 0; }
static void __exit dfir_exit(void) { printk(KERN_INFO “Goodbye, DFIR!\n”); }
module_init(dfir_init); module_exit(dfir_exit);
MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Stephan Berger”); MODULE_DESCRIPTION(“Simple Kernel Module for teaching Linux hardening techniques”); MODULE_VERSION(“0.1”);
Next, We create a file called Makefile in the same directory as our dfir.c source file:
obj-m += dfir.o
all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
And we compile our kernel module:
make
We see a lot of output, but the main thing to focus on is the filename of our compiled Kernel module, dfir.ko:
make -C /lib/modules/6.8.0-31-generic/build M=/root modules make[1]: Entering directory ‘/usr/src/linux-headers-6.8.0-31-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.2.0-23ubuntu4) 13.2.0 You are using: gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0 CC [M] /root/dfir.o MODPOST /root/Module.symvers CC [M] /root/dfir.mod.o LD [M] /root/dfir.ko BTF [M] /root/dfir.ko Skipping BTF generation for /root/dfir.ko due to unavailability of vmlinux make[1]: Leaving directory ‘/usr/src/linux-headers-6.8.0-31-generic’
We load the module with the command insmod:
insmod dfir.ko
Checking the logs (the command dmesg displays the message buffer of the kernel) if we see a successful load from our module - and yes, looks about right:
dmesg | tail
[..] [19323.400599] Hello, DFIR!
Same for unloading with the command rmmod:
rmmod dfir
dmesg | tail
[..] [19388.285645] Goodbye, DFIR!
Hardening
As stated above, the kernel setting modules_disabled is not enabled by default:
cat /proc/sys/kernel/modules_disabled
0
Let’s enable the feature to see the impact of it:
echo 1 > /proc/sys/kernel/modules_disabled
Once set, all subsequent attempts to load or unload kernel modules will fail. This change is permanent for the running kernel session and cannot be reverted without a reboot. Ensure all necessary modules are loaded before enabling this setting, as any attempt to load additional modules post-enablement will fail. As we see here, it’s not possible anymore to load our kernel module:
insmod dfir.ko
insmod: ERROR: could not insert module dfir.ko: Operation not permitted
And switching the flag back is not possible too, only after a reboot of the machine:
sysctl -w kernel.modules_disabled=0
sysctl: setting key “kernel.modules_disabled”: Invalid argument
And the unloading of already loaded modules is also not possible:
sysctl -w kernel.modules_disabled=1
kernel.modules_disabled = 1
rmmod dfir
rmmod: ERROR: ../libkmod/libkmod-module.c:856 kmod_module_remove_module() could not remove ‘dfir’: Operation not permitted rmmod: ERROR: could not remove module dfir: Operation not permitted
Conclusion
The kernel.modules_disabled parameter in the Linux kernel provides a robust security feature by preventing the loading and unloading of kernel modules, thereby hardening the system against low-level attacks, such as those involving rootkits. However, by default, this setting is disabled.