第 2 部分深入探讨了 LKM(可加载内核模块)和内核空间 rootkit 的世界,以探索 LKM 是什么、攻击者如何滥用它们以及如何检测它们
在本系列的上一部分中,我们介绍了LD_PRELOAD用户空间 rootkit。我们了解了这些 rootkit 的工作原理,并提供了在操作系统上检测它们的最佳实践。
在 Linux(和其他类 Unix 操作系统)中,系统内存分为两个不同的域:用户空间和内核空间。这些空间代表内存的不同区域,服务于不同的目的,在用户级应用程序和操作系统的核心功能(内核)之间提供了根本的分离。两个空间之间的分离增强了系统的稳定性、安全性和整体性能。
在本系列的第 2 部分中,我们将探讨 LKM(可加载内核模块)内核空间 rootkit。这种 rootkit 技术已被不同的攻击者在野外使用,包括:
-
TeamTNT,它使用 Diamorphine 开源 LKM rootkit 来隐藏加密货币挖掘过程。
-
Winnti 组 (APT 41) 使用 adore-ng 和 suterusu LKM rootkit 来隐藏不同的恶意活动。
在这篇文章中,我们将研究什么是可加载的内核模块,攻击者如何滥用此功能,提供在野外使用的示例,并解释如何检测它。
可加载的内核模块
Linux 内核是操作系统的核心,它管理系统资源并为操作系统和应用程序的其他部分提供基本服务。可加载内核模块是可以动态加载到 Linux 内核中以扩展其功能的代码片段,而无需重新编译内核甚至重新启动。例如,当您需要处理内核不支持的新型文件系统时,您可能需要加载一个特定的内核模块,该模块旨在为该文件系统类型提供支持。
可加载内核模块被设计为可在运行时加载,允许内核适应不同的硬件配置,并支持各种设备和功能,而无需重新编译或修改主内核代码。
从用户空间探索内核模块并与之交互
Linux 提供了各种命令来管理内核模块,以下模块是 kmod 应用程序的一部分。这些命令包括:
-
insmod
:用于手动将内核模块插入到正在运行的内核中。 -
rmmod
:用于卸载(删除)内核模块。 -
modprobe
:一个高级模块管理工具,不仅可以加载模块,还可以处理模块依赖关系,在需要时自动加载相关模块。 -
lsmod
:用于列出所有加载的内核模块。它通过从 /proc/modules 文件中读取信息并查询 /sys/module/ 目录以获取每个模块的详细信息来运行。
通常,用户不会直接调用 kmod,因为它主要由包管理器和系统工具来有效地处理内核模块。
三个相关文件和目录是:
-
/lib/modules/ - 包含特定于系统上安装的不同内核版本的内核模块和相关文件。/lib/modules/ 中的每个子目录都对应于特定的内核版本,并包含相关组件。它允许操作系统将不同的内核版本及其相关模块分开,从而在需要时更轻松地在内核版本之间切换。
-
/proc/modules - 此虚拟文件提供当前加载的内核模块列表。此文件中的每一行都表示一个已加载的模块,并包含有关该模块的信息,包括其名称、大小和使用计数。
-
/sys/module/ - 此虚拟目录提供有关当前加载的内核模块的信息。每个加载的模块在 /sys/modules/ 下都有自己的目录,在每个模块的目录中,都有包含有关模块信息的不同文件。此目录允许用户空间进程、工具和管理员在运行时访问有关已加载内核模块及其属性的信息。
系统调用(系统调用)和内核函数
在我们深入研究攻击者如何滥用 LKM 之前,了解什么是系统调用和内核函数非常重要。
当用户空间程序需要执行需要与内核交互的任务(例如,读取文件、创建网络套接字、管理进程)时,它必须要求内核执行这些操作。系统调用充当用户空间和内核空间之间的接口,允许内核代表用户程序执行请求的操作。浏览 Linux syscalls 手册页,了解有关 syscalls 的更多信息。
系统调用是一种从用户空间调用内核中函数的方法,但绝大多数内核代码并不公开为系统调用,而是由内核在内部用于执行与管理系统资源和维护操作系统整体操作相关的各种任务。它们不是用户程序可以通过系统调用访问的标准化接口的一部分。
例: 执行
strace ls
“strace ls”输出
在上面的代码片段中,我们可以看到getdents64