jonbttt/rk-veil

GitHub: jonbttt/rk-veil

面向 Linux 6.x 内核的 LKM rootkit 安全研究项目,演示了 syscall 挂钩、进程/文件隐藏与权限提升等核心技术的实现原理与检测方法。

Stars: 3 | Forks: 0

# rk-veil 一个简单的 Linux 可加载内核模块 (LKM) rootkit,目标是 kernel 6.x,作为一个安全研究和作品集项目而构建。它演示了核心的 rootkit 技术,包括 syscall 表挂钩、模块自我隐藏、文件和进程隐藏以及权限提升。 ## 功能 | 功能 | 机制 | |---|---| | 模块自我隐藏 | 从 kernel 模块列表中解除链接,移除 `/sys/module/` 条目 | | 文件隐藏 | `getdents64` 挂钩剥离以 `rkveil_` 为前缀的条目 | | 进程隐藏 | `execve` 挂钩根据 `argv[0]` 前缀自动隐藏进程 | | 权限提升 | `kill` 挂钩在接收到信号 64 时触发 `commit_creds` | ## 工作原理 ### syscall 表解析 在 kernel >= 5.7 上,`kallsyms_lookup_name()` 不再导出给模块。rk-veil 通过在该符号上注册 kprobe,在运行时对其进行解析。kernel 使用函数地址填充 `kp.addr`,随后将其转换为函数指针,并直接用于定位 `sys_call_table`。 ### 写保护绕过 在 kernel >= 5.4 上,syscall 表页在页表条目级别被标记为只读,这使得传统的 CR0 WP-bit 方法不再有效。rk-veil 使用 `lookup_address()` 查找 syscall 表页的 PTE,并在修补前直接设置 `_PAGE_RW` 位,之后将其恢复。 ### 模块自我隐藏 `THIS_MODULE` 从 kernel 的双向链表模块列表中解除链接,使其对 `lsmod` 和 `/proc/modules` 不可见。`kobject_del()` 移除 `/sys/module/` 条目。 ### 文件和进程隐藏 `getdents64` 挂钩将 dirent 缓冲区复制到 kernel 空间,剥离任何名称以 `rkveil_` 开头或数字名称匹配隐藏 PID 的条目,然后将修改后的缓冲区复制回 userspace。文件和 `/proc/` 条目都通过这种方式隐藏。 ### 自动进程隐藏 `execve` 挂钩在新进程映像加载之前检查 `argv[0]`。如果它以 `rkveil_` 开头,则在成功执行 exec 后将该 PID 添加到隐藏列表。`exit_group` 挂钩在进程退出时移除该 PID,以防止出现过期条目。 ### 权限提升 `kill` 挂钩拦截信号 64(一个未使用的实时信号)作为后门触发器。收到信号后,`prepare_creds()` 克隆调用进程的凭证,所有 uid/gid 字段都被清零,`commit_creds()` 原子性地将它们替换进去。该信号被消耗并且永远不会被传递。 ## 用法 ### 前置条件 - Linux kernel 6.x (在 6.2.0-25-generic 上测试) - `linux-headers-$(uname -r)` - `build-essential` ### 构建 ``` make ``` ### 加载 ``` sudo insmod rk_veil.ko sudo dmesg | grep rk-veil ``` ### 隐藏文件或目录 ``` # 任何以 rkveil_ 为前缀的文件或目录都会对 ls、find 等隐藏。 touch rkveil_secret.txt ls | grep rkveil # returns nothing ``` ### 隐藏进程 ``` # 使用以 rkveil_ 为前缀的 argv[0] 启动任何进程 (exec -a "rkveil_backdoor" sleep 60) & ps aux | grep rkveil # returns nothing ``` ### 权限提升 ``` whoami # vagrant (or any unprivileged user) kill -64 1 whoami # root ``` ### 卸载 ``` # 注意:加载后 rmmod 将会失败,因为该模块已从列表中隐藏。 # 重启 VM 以干净地卸载。 sudo reboot ``` ## 测试 包含完整的行为测试套件: ``` sudo bash test.sh ``` 测试涵盖模块隐藏、文件隐藏、进程自动隐藏、多个同时隐藏的进程、权限提升、syscall 表解析以及正常信号传递。 预期结果:**18/18 通过**。 ## Kernel 兼容性 | Kernel | 状态 | |---|---| | 6.2.x | 已测试,正常工作 | | 5.7 -- 6.1 | 应该可以工作(支持 kprobe 解析,需要 PTE 绕过) | | < 5.7 | 不受支持(kallsyms_lookup_name 曾被导出,需要使用不同的方法) | ## 测试环境 Vagrant + VirtualBox,`bento/ubuntu-22.04` 搭配 kernel `6.2.0-25-generic`。 仓库中包含一个 `Vagrantfile`。要开始使用: ``` vagrant up vagrant ssh ``` 在 `vagrant ssh` 之后,安装特定的 kernel 版本: ``` sudo apt update sudo apt install -y linux-image-6.2.0-25-generic linux-headers-6.2.0-25-generic sudo reboot ``` 重启后进行验证: ``` uname -r # should show 6.2.0-25-generic ``` ## 检测 此 rootkit 可通过以下方式检测: | 检测方法 | 描述 | |---|---| | **syscall 表完整性检查** | 将当前的 syscall 表条目与已知正常值进行比较 | | **基于 eBPF 的监控** | 像 Falco 或 Tetragon 这样的工具可以检测到异常的 kernel 函数调用,而不管 userspace 的隐藏情况如何 | | **直接访问 `/proc`** | 隐藏仅限于列表显示;如果 PID 已经知道,进程仍然可以通过直接路径访问 | | **KASLR 绕过检测** | kprobe 解析技术留下了一个短暂的 kprobe 注册窗口,可以通过 `/sys/kernel/debug/kprobes/` 观察到 | | **模块列表交叉引用** | 比较 sysfs 中的 `kobject` 条目与模块列表可以揭示隐藏的模块 | ## 参考文献 - [xcellerator 的 Linux Rootkits 系列](https://xcellerator.github.io/posts/linux_rootkits_01/) - [Linux Kernel 模块编程指南](https://sysprog21.github.io/lkmpg/) - [Caraxes — 学术 LKM rootkit](https://github.com/ait-aecid/caraxes) ## 作者 [jonbttt](https://github.com/jonbttt)
标签:CSV导出, Linux内核, LKM, Rootkit, Zeek, 协议分析, 子域名枚举, 客户端加密, 应用安全, 权限提升, 私有化部署, 系统安全, 防御规避