通过 LD_PRELOAD 进行动态链接器劫持是一种 Linux rootkit 技术,由不同的攻击者在野外使用。在本系列的第一部分中,我们将讨论此威胁并说明如何检测它。
Rootkit 通常是攻击者用来完全控制受感染资源并隐藏恶意活动的一种恶意软件。它们通常是持续性攻击活动的一部分,例如窃取敏感信息或进行间谍活动。Rootkit 可能难以检测和删除,因为它们利用高级技术来隐藏它们在系统上的存在。
为了实现不同的功能,rootkit 会拦截和更改正常的执行流程。拦截可以位于操作系统的不同层,包括用户空间级代码和内核级系统调用。
在本系列文章中,我们将重点介绍 Linux,因为它是云中的主要操作系统。我们将介绍三种不同的 Linux rootkit 技术:动态链接库劫持(LD_PRELOAD)、Linux kernel module(LKM) rootkit 和 eBPF rootkit。首先,我们将探讨用户态LD_PRELOAD rootkit 技术。我们将分析它,提供它在野外使用的示例,并解释如何检测它。
Linux 动态链接器
在我们深入研究技术本身之前,让我们先了解一下 Linux 动态链接器是什么。
在 Windows 和 Linux 等现代操作系统中,程序可以静态或动态链接。静态链接的二进制文件与执行所需的所有依赖项(库)一起编译。动态链接的二进制文件使用位于操作系统上的共享库。这些库将在运行时解析、加载和链接。负责此操作的 Linux 组件是动态链接器,也称为ld.so或ld-linux.so.*。
让我们自己实验一下:
让我们看一下二进制文件ls。
1. ldd该命令允许我们检查 ELF 的依赖项和共享库。打开终端并运行ldd ls。在输出中,我们可以看到二进制文件使用了libselinux、libc.so.6和libpcre库。第一个列出的依赖项是虚拟动态共享对象,这是一个常见的共享库,由内核自动映射到所有用户空间应用程序的地址空间中。最后列出的依赖库是动态链接器位置。
2. 接下来,运行strace ls,在下面的输出中,可以看到相应的库在执行时加载到内存中。
如果我们再看一下输出,系统会在加载之前检查是否存在/etc/ld.so.preload(第一个红框上方的五行)。这将我们引向下一节LD_PRELOAD。
LD_PRELOAD
Linux 动态链接器提供了一项重要功能叫做LD_PRELOAD。它保存用户指定的ELF共享对象的列表,使用户能够在任何其他共享库之前以及程序本身执行之前将这些共享对象加载到进程的地址空间中。此功能有多种用途,包括调试、测试和运行时检测,可以通过写入文件/etc/ld.so.preload或使用环境变量LD_PRELOAD来使用。
虽然它有许多合法用途,但攻击者也可以利用它,因为它允许覆盖动态链接程序使用的现有功能。此功能还使它们能够逃避检测、拦截机密并通常更改系统行为。
让我们自己实验一下:
在检查ls源代码时,我们可以看到 libc的ls函数用法。ls使用循环readdir函数的方式逐个读取目录条目。
该函数返回指向 dirent 结构的指针,该结构包含有关目录条目的信息,例如名称。一旦它返回 NULL,它就指向目录的末尾。
让我们创建一个库,修改readdir函数用以隐藏名为“malicious_file”的文件,编译它,并将其添加到LD_PRELOAD
1. 创建目录/tmp/working-dir-test并将以下代码复制到此目录下的文件hijackls.c中
代码语言:txt复制
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <dirent.h>
#include <string.h>
// Function pointer typedef for the original readdir ls function
typedef struct dirent* (*ls_t)(DIR*);
// Interposed ls function
struct dirent* readdir(DIR* dirp) {
// Get the original readdir address
ls_t original_readdir = (ls_t)dlsym(RTLD_NEXT, "readdir");
struct dirent* entry;
do {
// Call the original ls function to get the next directory entry
entry = original_readdir(dirp);
// Check if the entry is the file we want to hide
if (entry != NULL && strcmp(entry->d_name, "malicious_file") == 0) {
// Skip the file by calling the original ls function again
entry = original_readdir(dirp);
}
} while (entry != NULL && strcmp(entry->d_name, "malicious_file") == 0);
return entry;
}
在上面的预加载库代码中,我们定义了一个函数readdir,该函数充当插入函数,并在执行ls命令时调用经过修改的readdir而不是原始readdir函数。在我们的插入函数中,我们使用dlsym获取原始函数的地址,然后调用它来获取下一个目录条目。我们将每个条目的名称与“malicious_file”进行比较,如果匹配,则跳过它,从而有效地将该文件从输出中隐藏起来。
dlsym允许我们在运行时获取共享对象/库中函数的地址。使用 dlsym 中的RTLD_NEXT句柄,我们可以找到并调用原始readdir函数。
2. 将代码编译为共享对象:
代码语言:javascript复制gcc -shared -fPIC -o /tmp/working-dir-test/libhijackls.so /tmp/working-dir-test/hijackls.c -ldl
3. 在其下创建一个目录,并在其中填充项目:
代码语言:javascript复制mkdir /tmp/ld-preload-test && cd /tmp/ld-preload-test && for i in file_1 file_2 malicious_file; do touch $i; done;
4. 运行ls并检查所有目录条目。
5. 导出到LD_PRELOAD共享对象的位置:
代码语言:javascript复制 export LD_PRELOAD=/tmp/working-dir-test/libhijackls.so
6. 再次运行ls,您将看到我们成功劫持了该函数,并且输出不包含“malicious_file”。
7. 最后,通过运行unset LD_PRELOAD取消设置环境变量。
LD_PRELOAD和/etc/ld.so.preload之间的区别
/etc/ld.so.preload是一个系统范围的配置文件,适用于所有进程并影响整个系统。访问此文件需要 root 权限。不同的是,LD_PRELOAD是一个环境变量,它允许单个用户为每个进程指定要为特定可执行文件或命令预加载的库。因此,您无需成为 root 用户即可使用它。LD_PRELOAD定义的库在/etc/ld.so.preload中的库之前加载。
在野的利用
动态链接器劫持 rootkit 技术已被许多攻击者使用。虽然有些人从头开始生成逻辑,但也有人使用公开可用的开源工具。以下是一些示例:
- Winnti for Linux – 这种来自中国的后门工具由用户模式 rootkit 和主后门组成。用户模式 rootkit 在很大一部分基于开源 Azazel rootkit。Azazel 用于隐藏进程、网络连接、文件和目录,还包含后门功能。Winnti for Linux 利用 Azazel 来隐藏主后门的恶意活动。
- TeamTNT – 该小组在不同的活动中使用了libprocesshider。Libprocesshider 是一个开源工具,旨在通过覆盖函数来隐藏常用进程列表工具(如 ps、top 和 lsof)中的特定进程。这种技术使TeamTNT能够隐藏XMRig加密和其他恶意进程。
- Symbiote – 与之前的例子不同,Symbiote 既是一个后门,也是一个自主开发的 rootkit。Symbiote 通过在 libc和libpcap中hook函数来隐藏其恶意活动。它还使用这些功能通过hook libc的read函数并检查调用它的进程是ssh还是scp来窃取凭据。Symbiote 利用其 rootkit 功能通过挂接 Linux 可插入身份验证模块(PAM)函数并使用硬编码密码匹配绕过身份验证机制来远程访问计算机。
- OrBit – OrBit 是一个动态链接器劫持 rootkit,由一个dropper 和一个恶意共享对象组成。dropper的任务是确保在任何其他对象之前加载共享对象。为了确保这一点,OrBit 使用了两种技术:将对象路径添加到/etc/ld.so.preload并通过修改字符的方式将加载程序的二进路径修改为恶意软件提供的专用路径。与 Symbiote 类似,OrBit 在libc 、libpcap和 PAM 中挂钩函数,以收集凭据、逃避检测、获得持久性并提供远程访问。
检测滥用LD_PRELOAD行为
正如我们在前面的示例中看到的,攻击者使用不同的用户空间函数来hook,使得调查受感染的机器变得困难。以下检测方法可以帮助您确定是否感染了这种类型的 rootkit:
- 对于/etc/ld.so.preload:文件中的更改将写入磁盘。建议使用镜像快照检查此文件。如果您发现异常的库路径,请检查它。
- 对于LD_PRELOAD:搜索使用意外环境变量执行的进程(每个进程的所有环境变量都位于/proc/{pid}/environ下)。如果您发现不常见的库路径,请检查它。
- 将运行时文件系统与镜像快照进行比较。如果存在差异,则这些文件可能是隐藏在某些命令中的攻击的一部分。
- 如果在容器上使用运行时检测工具,请确保它支持加载到内存中的偏移执行库。偏移执行检测在部署容器后添加或修改的可执行文件。
- 利用取消隐藏等工具。取消隐藏使用不同的暴力破解技术来检测隐藏的进程。
总结
动态链接器劫持方式是一种 Linux rootkit 技术,被不同的威胁参与者在野外使用。成功部署此 rootkit 的攻击者可以对受感染的资源进行强大的控制,并且可以从许多功能中受益,例如隐藏恶意活动和拦截凭据收集功能。
在这篇博文中,我们了解了此 rootkit 的工作原理,并提供了有关如何在操作系统上检测它的最佳实践。请继续关注本系列的第 2 部分,我们将深入探讨 Linux 内核模块 (LKM) rootkit。