进程隐藏的类别
隐藏进程的方法分为两类,一类是用户态隐藏,另一类是内核态隐藏。用户态常使用的方法有很多,例如劫持预加载动态链接库,一般通过设置环境变量 LD_PRELOAD 或者 /etc/ld.so.preload,过滤 /proc/pid 目录、修改进程 PID 等等。内核态隐藏进程一般是加载恶意的内核模块实现进程隐藏。
/etc/ld.so.preload 是什么?
ld.so.preload 是 Linux 系统动态链接器 ld.so 的配置文件之一。它的作用是:强制在所有动态链接程序运行前,预先加载指定的 .so 动态库。
被滥用的方式(尤其是挖矿木马)
滥用方式 | 说明 |
---|---|
🥷 隐藏进程 | 劫持 readdir()、getdents(),让你看不到挖矿进程 |
🕳️ 隐藏文件 | Hook stat()、fopen(),隐藏指定的二进制文件或配置文件 |
🦠 执行后门 | 注入 .so 实现命令注入、反向 shell |
🧩 持久化启动 | 即使你重启系统,ld.so.preload 仍会强制加载恶意 .so |
🔒 隐蔽持久 | 攻击者会 chattr +i 锁定该文件,无法直接修改或删除 |
攻击链与防御
动作 | 利用方式 | 关键函数 | 防御建议 |
---|---|---|---|
进程隐藏 | 过滤 /proc 目录 | readdir, getdents | 检查 /proc 与 ps 是否一致 |
文件隐藏 | 避免被发现/查杀 | open, stat, fopen | ldd, strace 检查程序行为 |
后门命令 | hook execve 注入命令 | execve | 审查 /proc/*/exe |
持久启动 | preload 配置 | /etc/ld.so.preload | 加锁 + 审计 |
隐蔽持久 | 加不可变属性 | chattr +i | 检查文件属性 |
通过劫持getdents() 或 readdir()来隐藏进程,编译后将生成的 .so 文件路径写入 /etc/ld.so.preload。运行该进程后可以看到 ps 命令未检测到隐藏进程。但是使用 busybox 可以看到隐藏进程的相关信息,那是因为 busybox ps 命令直接读取了 proc 目录的数字,不调用系统预加载库。
LD_AUDIT和LD_PRELOAD劫持预加载动态链接来隐藏进程如何处置应急
- 你可以通过以下命令来查看当前系统是否存在这些环境变量:
echo $LD_PRELOAD
echo $LD_AUDIT
如果它们被设置为某些非系统库路径(如 /tmp/malicious.so),就说明系统可能已经被劫持。
- 清理和禁用 LD_AUDIT 和 LD_PRELOAD 环境变量
通过清除或禁用这些环境变量,确保没有恶意 .so 文件被加载。
unset LD_PRELOAD
unset LD_AUDIT
- 查看 /etc/ld.so.preload 文件
如果文件中有可疑的 .so 路径(例如 /tmp/malicious.so),说明恶意库已经被加载。
> /etc/ld.so.preload` # 清空文件
- 通过 ps、top 和 ls /proc 等命令,你可能无法看到被隐藏的进程。为了确认这些进程是否真正存在,你可以直接通过读取 /proc/ 目录来查看。
ls /proc | grep -E '^\d+$' # 列出所有 PID 目录
如果你发现某个进程目录存在,但 ps 或 top 命令没有列出该进程,说明它可能被隐藏了。
加固措施:
- 预防措施
- 限制 LD_PRELOAD 和 LD_AUDIT 使用: 禁止普通用户使用 LD_PRELOAD 和 LD_AUDIT 环境变量。
- 通过修改 /etc/security/limits.conf 文件,限制用户设置这些环境变量的能力。
- 强化系统配置:
- 使用 SELinux 或 AppArmor 进一步限制进程和文件访问权限。 加密和保护
- /etc/ld.so.preload,通过设置文件权限和使用 chattr 防止被篡改。
通过修改进程pid来实现进程隐藏
如果攻击者通过内核模块修改进程的 PID(例如将其改为一个不常见的数字,或使其脱离 PID 范围),那么该进程对应的 /proc/ 目录就会消失,因为 /proc 目录是由内核根据 tasklist 和进程的 PID 来动态创建的。
应对措施
-
网络活动:即使进程的 /proc 目录被隐藏,网络连接仍然是它的一个泄漏点。通过查看 /proc/net 目录下的 TCP 和 UDP连接,你可以发现进程是否在进行网络通信。
-
内核级监控:如果普通用户空间工具无法检测隐藏的进程,可以通过内核模块直接访问 tasklist 和 socket
结构来关联进程和网络连接。 -
实时监控:使用如 ss, netstat, auditd 等工具定期扫描网络连接,检查是否存在异常连接或网络活动。
-
安装 stap 后默认会在路径 /usr/share/systemtap/examples/ 下存储一些非常实用的脚本。例如 network- 目录下脚本主要查看系统中每个进程的网络传输情况,io 目录下的脚本主要查看进程对磁盘的读写情况。虽然隐藏了进程,但是还存在网络连接。故可以通过 network 目录的脚本从内核层面检测当前操作系统的网络连接获取隐藏进程。
-
假设系统的 PID 范围是 1 到 131072,攻击者可能会将进程的 PID 设置为一个不在这个范围内的值(例如:131073 及以上)。
需要遍历 PID 范围之外的 PID(例如,大于 131072 的值)来检测是否存在隐藏进程。
通过 kill 命令发送信号:可以编写一个脚本,遍历这些 PID 范围外的值,并通过 kill -20 命令发送信号来检查是否有进程存在并响应信号。
如果进程存在并能处理信号,kill 命令会成功返回。如果 PID 不存在,则会返回 “No such process” 错误。
伪造内核模块隐藏进程
在 Linux 上,有许多内核进程被创建来帮助完成系统任务。这些进程可用于调度、磁盘 I/O 等。当使用像 ps 之类的命令显示当前运行的进程时,内核进程的周围有[括号],普通进程通常不会显示带方括号的进程。Linux 恶意软件使用各种技术来隐藏检测。其中一种为让进程名显示 [] 来模拟内核线程。
(1) /proc/maps 通常用来查看进程的虚拟地址空间是如何使用的。正常的内核进程 maps 内容为空的,伪装的内核进程是有内容标识的。如下 pid 为 2120 为系统正常的内核进程,pid 为 3195 是伪造的内核进程。
(2) /proc/exe 指向运行进程的二进制程序链接,正常内核进程没有相应的二进制文件,恶意的内核进程有对应的二进制文件。