Skip to content

A Linux kernel rootkit in Rust using a custom made type-2 hypervisor, eBPF XDP and TC programs

License

Notifications You must be signed in to change notification settings

DualHorizon/blackpill

Repository files navigation

BlackPill

BlackPill is a stealthy Linux rootkit made in Rust.

Open issues Commit activity License

Features

The rootkit is composed of multiple modules (talking about Rust modules, not kernel modules):

  • defense evasion: hide files, processes, network connections, etc.
  • hooking: hook syscalls and IDT
  • hypervisor: create a virtual machine to execute malicious code
  • persistence: make the rootkit persistent after reboot and resilient to supression
  • utils: various utilities

The architecture looks as the following:

Rootkit simple architecture schema

And here is how malicious code is executed from C2 to VM guest:

Rootkit code execution sequence diagram

C2 sends crafted assembled x86_64 mnemonics to the rootkit, which then sends it to the VM guest to execute it. The VM guest is isolated from the host and can be used to execute malicious code.

Kernel do not see incoming malicous packets as they are filtered by the eBPF XDP program and sent to the LKM module, and outgoing packets are modified by the eBPF TC program.

Important

This project is still a work-in-progress. Not all features are working!
Feel free to submit issues or pull requests.

Hooking

Hooking is a fundamental capability of the rootkit, implemented using kprobes in the Linux kernel. This technique intercepts and redirects the execution of system functions to monitor or modify their behavior. In the context of this rootkit, kprobes provides a powerful mechanism to interact with kernel functions without altering the source code directly.

Defense Evasion

To ensure stealth, the rootkit employs two primary anti-detection mechanisms:

  1. Removing the Module from the Kernel Module List
    When a kernel module is loaded, it is added to the kernel's module list, visible via tools like lsmod or /proc/modules. To prevent detection:

    • The rootkit manually removes itself from this list.
    • Despite being removed from the list, the module remains operational, enabling continued execution of its functionality.
  2. Hooking the filldir64 Function to Hide a Specific Directory
    To conceal files used by the rootkit, a hook is implemented on the filldir64 function. This function is invoked when a process reads directory contents (e.g., via getdents or readdir system calls).

    • Hooking Process:
      • The rootkit intercepts the filldir64 function using kprobes.
      • During execution, the handler inspects directory entries returned to the user.
      • If an entry matches the /BLACKPILL-BLACKPILL directory (used to store critical rootkit files), it is filtered out and not returned to the user.
      • All other directory entries are returned normally, ensuring transparency for user-space tools.
  3. Using eBPF XDP and TC Programs to Modify Ingress and Egress network traffic To normalize our malicious network communications, we use eBPF XDP (eXpress Data Path) and TC (Traffic Control) programs. As such, we can:

    • Intercept specific incoming (ingress) packets with the XDP program at the lowest network level by matching the crafted TCP payload signature from our C2, which we then redirect to a custom BPF map for VM/LKM processing.
    • Intercept specific outgoing (egress) packets with the TC program by matching TCP packets generated by VM/LKM, which we then modify by overwriting their payload with our C2 response data. The original packets are automatically retransmitted by TCP, maintaining the appearance of legitimate traffic.

Hypervisor

  1. Initial System Configuration

    • Enable hardware virtualization extensions (Intel VT-x or AMD-V) in the BIOS/UEFI.
    • Configure the control registers (CR0, CR4, and IA32_EFER) to switch into VMX (Virtual Machine Extensions) or SVM (Secure Virtual Machine) mode.
  2. Entering VMX or SVM Mode

    • Initialize the virtualization-specific data structures (VMCS for Intel or VMCB for AMD).
    • Program the processor features, such as VM exits, to handle interactions between the guest and the host.
  3. Managing Transitions Between Host and Guest

    • Configure the entry and exit points for virtual machines (VM entry/exit).
    • Implement logic to intercept sensitive system calls made by the guest and analyze their effects.
  4. Guest System Creation

    • Allocate memory for the guest and initialize its resources (registers, stack, etc.).
  5. Communication

    • Use communication channels between the rootkit and the hypervisor to transmit commands or data.

Follow these steps to implement a basic hypervisor, ensuring that hardware configurations and system resources are properly managed for a secure and functional environment.

Persistence

Persistence is a critical capability of any rootkit, enabling it to maintain control over the target system even after a reboot.
In its current implementation, the persistence mechanism demonstrates its functionality by creating a test file in the file system using the /bin/touch command. This placeholder action showcases the rootkit's ability to execute privileged operations and can be extended to implement more advanced persistence strategies.

Setup Development Environment

Multiple steps needs to be done before compiling our rootkit. The development environment is composed of :

  • a simple Alpine Linux image providing essential tools
  • a custom compiled kernel with Rust activated
  • a simple QEMU virtual machine accelerated by KVM

Start by cloning the repository and its shallow submodules :

git clone [email protected]:DualHorizon/blackpill.git --recursive --depth 1

Important Dependencies

On an arch-based distribution :

sudo pacman -S qemu-base qemu-desktop docker grub

Linux Kernel

On an arch-based Linux distribution, install Rust and other dependencies :

sudo pacman -S rust rust-src rust-bindgen
sudo pacman -S clang lld llvm

Then we'll need Rust sources and bindgen :

rustup component add rust-src clippy rustfmt
cargo install --locked bindgen-cli

Make sure you can start compiling your kernel with Rust by running in folder linux/ :

$ cd blackpill
$ pushd linux
$ make LLVM=1 rustavailable
Rust is available!
$ popd

Launch the first time setup task which configures and compiles the kernel :

make first-time-setup

Important

If you are asked of customizing options, press Enter each time.

Rootkit

You can compile the Rust kernel module (out-of-tree) with :

make

Launch the VM with :

make vm

Inside the VM, you are auto logged in root. You can enable the module:

$ modprobe blackpill
# you can check kernel logs with
$ dmesg

Usage

Local Privilege Escalation

Once the vm started you can use the command above to escalate your privileges:

mkdir ImFeelingRootNow_<PID>

Replace <PID> with the process id of the process you want to escalate the privilege to.

C2

Setup the python client:

cd blackpill-c2
poetry install
poetry shell
python client.py

After launching the client with your args ([ip] [port]) you should get:

$ python client.py 0.0.0.0 1339
Connected to rootkit!

Then you can use the help command to display available commands:

blackpill: help
Available Commands
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ CommandDescription                                             ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ read_virt_memory <address>Read 4 bytes (32 bits) memory at 'address'              │
│ write_virt_memory <address> <value>Write 4 bytes (32 bits) memory at 'address'             │
│ launch_userland_binary <path>Launch a userland binary at 'path'                      │
│ change_msr <msr> <value>Change the value of a Model Specific Register (MSR)     │
│ read_phys_memory <address> <value>Read 4 bytes (32 bits) of physical memory at 'address'  │
│ write_phys_memory <address> <value>Write 4 bytes (32 bits) of physical memory at 'address' │
│ stop_executionStop the execution of the guest VM                      │
│ change_vmcs_field <field> <value>Change a VMCS field to 'value'                          │
│ helpShow this help message                                  │
└─────────────────────────────────────┴─────────────────────────────────────────────────────────┘

Credits

Environment setup:

About

A Linux kernel rootkit in Rust using a custom made type-2 hypervisor, eBPF XDP and TC programs

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors 4

  •  
  •  
  •  
  •