0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
一直想写个Linux 内核Rootkit技术简介,现在把阶段性研究成果总结如下。
使用HOOK技术(kprobe、ftrace、 livepatch)实现进程、内核模块的隐藏。 测试环境是ubuntu 20.04 kernel v5.4。 本研究项目,仅用于研究和演示目的,禁止用于非法目的。 使用前,请认真阅读相关法律,如《中华人民共和国网络安全法》等相关法律,由使用不当引起的后果与本作者无关。
Rootkit的基本要求
不落磁盘、不调用系统命令、隐藏自己、反检测、反取证、使用隐通道通信。这些要求的最终目的是可以持续的存在系统中,提供最高权限的控制,而不是破坏。
基本架构
agent和管理端。管理端不做介绍。
agent分为内核与应用两部分:
内核:1. 实现上面提到的基本要求; 2. 提供应用层不容易实现的功能。
应用:实现具体的功能。例如收集各种密钥,发送数据。
内核部分功能
1. 隐藏多个进程。 根据程序的全路经或者进程的comm隐藏。
2. 根据内核模块名隐藏内核模块。
3. bypass 通用检测工具。
4. bypass 通用取证。
5. 隐通道通信。
隐藏应用层进程
隐藏应用层进程需要从以下地方隐藏:
1. /proc 目录下不显示隐藏进程的pid目录及子目录。 一般proc 工具,如top、 ps 都是读取proc文件系统。
主要隐藏的操作:不能在/proc目录下读取到pid目录、不能chdir到隐藏进程pid目录。
2. 进程的fork/execv/exit等信息不能通过 cn_proc 发送到应用层。
cn_proc 是kernel中记录并发送进程相关活动的机制,其利用connector通道(netlink的一个子通道)与应用层通信。 一般的HIDS、EDR会利用该机制。
3. 不能使用trace相关工具查看到进程的相关信息。
内核中的trace技术即HOOK技术有:ftrace、 kprobe, livepatch、bpf。 应该在这些过程中过滤掉相关信息。
4. kernel 版本大于5.0.1, 不能使用fanotify监测到相关信息。
fanotify是监测文件状态变化的机制,在kernel v5.0.1及以上可以监测到文件的执行。 在使用该功能过程中过滤掉相关信息。
5. 一些取证工具,例如unhide,会遍历pid值,调用和pid相关的系统调用,检测是否有隐藏进程存在。
例如: kill系统调用 int kill(pid_t pid, int sig); 设置sig为0, 循环设置pid从1到最大值,调用该系统调用,如果返回0,则表示pid为设置值的进程存在。
该类系统调用很多,如getpriority、 sched_getscheduler、ptrace等等。
6. taskstats系统调用,可以取到进程的状态信息。应该从该系统调用中过滤掉。
7. acct是系统的记账功能。在进程退出时把进程的使用时间、pid、comm等信息记录在文件中,一般是/var/log/account/pacct文件中(也可以设置成其他文件)。
隐藏内核模块
隐藏内核模块从以下地方隐藏,在以下列出的地方不显示指定的内核模块信息。
1. /proc/module 文件。lsmod等命令读取该文件获得加载的内核模块名。
2. /proc/kallsyms 中显示的是内核中的符号。如果符号是内核模块中的,一并显示内核模块名。
3. /sys/module 目录。 该目录下是加载的内核模块信息,如参数。 以内核模块名为子目录。
4. /sys/kernel/livepatch/ 目录下是热补丁内核模块信息。例如内核模块以热补丁形式存在,需要从该目录下隐藏。
5. /sys/kernel/tracing/enabled_functions 文件是hook函数的相关信息,如果模块中有使用HOOK技术,需要从该文件中隐藏。
6. /proc/sys/kernel/tainted 显示有无污染内核。所谓污染,即是内核树外的模块加载。例如自己编译的但没有签名的模块加载,即在该文件中显示污染标志。
7. 内核的日志信息。 这个显而易见,审计、取证首先就是读取/var/log/下的 dmesg、kern、message等文件。
隐通道通信
所谓隐通道:机制设计之外的利用。
典型的就是ICMP echo携带的数据。ICMP协议基本上都不会被监测、限制,尽管也有限制ICMP流量的机制,但很容易绕过。其优点:基本不会被监测到或者监测成本巨大。
隐通道不仅仅指网络传输,如系统调用、进程间通信等等,都可以被利用。
在七层网络协议中,每一层都有隐通道。如传输层, 利用syn、 rst 、rst序列传输信息。 应用层,在图片、视频中传输信息,也是成熟的技术。
例如:
反取证的手段
1. 以上的隐藏手段,足够绕过大部分取证工具。一些读取内存的工具,例如kdump,直接禁止kdump文件的产生、或者使用垃圾数据填充kdump文件。应用层程序则禁止产上core文件。
2. 加载后使用安全删除工具清理加载程序。
3. 一些其他常用的操作: 加密壳、检测是否是调试模式、PTRACE_TRACEME等。
HOOK技术利用
内核原生提供的HOOK技术有ftrace、kprobe、livepatch。 uprobe也存在,但没有导出相应接口,稍加手段,也可以利用uprobe。古老的直接修改系统调用表技术,是“真黑客”技术,不是工程技术,有很大的宕机概率。
利用这些HOOK技术实现上面的目的,主要方法有:
1. 读取、发送信息时,进行过滤。例如读取/proc文件系统时、使用cn_proc发送时。
这种方式的优点是不影响内核的正常运行。
2. 直接把相关信息节点从内核中的相关数据结构中摘除。如 /proc/modules, 就是从内核模块全局链表中删除。
这种方式的优点是简单,但有些情况下会影响系统正常运行。
3. 拦截函数,修改参数或者返回值。例如,sys_kill, 判断是否是隐藏进程的pid, 如果是,则修改返回值为-ESRCH。
难点
1. 找到最佳HOOK点。HOOK范围大了,浪费资源。
2. 有些内核函数没有导出,就要想办法找到函数地址。
3. 一些最佳HOOK点是静态定义的,编译时内联。 这种情况最麻烦,需要hook该函数的内部函数,有时需要重新写该函数,就需要重定义大量的内部数据结构。
4. 几种HOOK技术的混用,会有前后逻辑的耦合,要细心处理。
5. 繁琐,测试时要频繁重启机器。
防御
1. 编译内核时禁用加载内核模块。
2. 启用验证内核模块签名。
3. 启动时启用secure boot。
4. 启动后lockdown系统。
QA:
1. 需要root权限, 作用不大。
考虑一下,其他应用层rootkit是怎么加载的,要不要root权限?
2. 禁止加载内核模块或者启用验证内核模块签名的情况下,没有作用。
确实这样的。 现实是还有大量的CentOS6 和没有启用验证内核模块签名的CentOS7。
3. ICMP 是不可靠的。
是的。 使用ICMP主要绕过NIDS,但对少量数据(5M以内)是可靠的。
实验源码:
https://github.com/z789/hide_proc
该实验项目2020年底开始,2021年4月第一次提交到github。 原创不易,欢迎点赞。
作者简介
安全老兵。最早接触内核代码v2.4,多年不辍。写代码纯属业余爱好。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)