{"id":28605681,"url":"https://github.com/DualHorizon/blackpill","last_synced_at":"2025-06-11T19:04:08.804Z","repository":{"id":271906477,"uuid":"859780635","full_name":"DualHorizon/blackpill","owner":"DualHorizon","description":"A Linux kernel rootkit in Rust using a custom made type-2 hypervisor, eBPF XDP and TC programs","archived":false,"fork":false,"pushed_at":"2025-01-10T16:27:04.000Z","size":289,"stargazers_count":320,"open_issues_count":6,"forks_count":40,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-23T17:18:18.286Z","etag":null,"topics":["ebpf","hypervisor","linux-rootkit","rootkit"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DualHorizon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-19T09:10:45.000Z","updated_at":"2025-05-22T19:44:24.000Z","dependencies_parsed_at":"2025-01-10T17:33:15.304Z","dependency_job_id":"4692b3cd-d895-44ef-b418-029126d438ff","html_url":"https://github.com/DualHorizon/blackpill","commit_stats":null,"previous_names":["dualhorizon/blackpill"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/DualHorizon/blackpill","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DualHorizon%2Fblackpill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DualHorizon%2Fblackpill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DualHorizon%2Fblackpill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DualHorizon%2Fblackpill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DualHorizon","download_url":"https://codeload.github.com/DualHorizon/blackpill/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DualHorizon%2Fblackpill/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259318621,"owners_count":22839625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ebpf","hypervisor","linux-rootkit","rootkit"],"created_at":"2025-06-11T19:01:30.289Z","updated_at":"2025-06-11T19:04:08.795Z","avatar_url":"https://github.com/DualHorizon.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eBlackPill\u003c/h1\u003e\n\u003cp align=\"center\"\u003eBlackPill is a stealthy Linux rootkit made in Rust.\u003cp\u003e\n\u003cdiv align=\"center\"\u003e\n\t\u003cimg alt=\"Open issues\" src=\"https://img.shields.io/github/issues/DualHorizon/blackpill?style=for-the-badge\u0026color=%23973B21\u0026labelColor=%230C1510\"\u003e\n\t\u003cimg alt=\"Commit activity\" src=\"https://img.shields.io/github/commit-activity/w/DualHorizon/blackpill?style=for-the-badge\u0026color=%23973B21\u0026labelColor=%230C1510\"\u003e\n\t\u003cimg alt=\"License\" src=\"https://img.shields.io/github/license/DualHorizon/blackpill?style=for-the-badge\u0026color=%23973B21\u0026labelColor=%230C1510\"\u003e\n\u003c/div\u003e\n\n## Features\n\nThe rootkit is composed of multiple modules (talking about Rust modules, not kernel modules):\n\n- **defense evasion**: hide files, processes, network connections, etc.\n- **hooking**: hook syscalls and IDT\n- **hypervisor**: create a virtual machine to execute malicious code\n- **persistence**: make the rootkit persistent after reboot and resilient to supression\n- **utils**: various utilities\n\nThe architecture looks as the following:\n\n![Rootkit simple architecture schema](assets/blackpill-rootkit-overview.drawio.png)\n\nAnd here is how malicious code is executed from C2 to VM guest:\n\n![Rootkit code execution sequence diagram](assets/blackpill-sequence-diagram.drawio.png)\n\nC2 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.\n\nKernel 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.\n\n\u003e [!IMPORTANT]  \n\u003e This project is still a work-in-progress.\n\u003e Not all features are working! \u003cbr\u003e\n\u003e Feel free to submit issues or pull requests.\n\n### Hooking\n\nHooking 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.\n\n### Defense Evasion\n\nTo ensure stealth, the rootkit employs two primary anti-detection mechanisms:\n\n1. **Removing the Module from the Kernel Module List**  \n   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:\n   - The rootkit manually removes itself from this list.\n   - Despite being removed from the list, the module remains operational, enabling continued execution of its functionality.\n\n2. **Hooking the `filldir64` Function to Hide a Specific Directory**  \n   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).\n\n   - **Hooking Process**:\n\t - The rootkit intercepts the `filldir64` function using `kprobes`.\n\t - During execution, the handler inspects directory entries returned to the user.\n\t - If an entry matches the `/BLACKPILL-BLACKPILL` directory (used to store critical rootkit files), it is filtered out and not returned to the user.\n\t - All other directory entries are returned normally, ensuring transparency for user-space tools.\n\n3. **Using eBPF XDP and TC Programs to Modify Ingress and Egress network traffic** \n   To normalize our malicious network communications, we use eBPF XDP (eXpress Data Path) and TC (Traffic Control) programs. As such, we can:\n\t- 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.\n\t- 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.\n\n### Hypervisor\n\nOur simple hypervisor was implemented following this :\n\n1. **Initial system configuration**\n\t- Enable hardware virtualization extensions (Intel VT-x or AMD-V) in the BIOS/UEFI (the rootkit doesn't do that, is must be enabled before).\n\t- Configure the control registers (CR0, CR4, and IA32_EFER) to switch into VMX (Virtual Machine Extensions (Intel)) or SVM (Secure Virtual Machine (AMD)) mode.\n\n2. Entering VMX or SVM Mode\n\t- Initialize the virtualization-specific data structures (VMCS for Intel or VMCB for AMD).\n\t- Program the processor features, such as VM exits, to handle interactions between the guest and the host.\n\n3. Managing Transitions Between Host and Guest\n\t- Configure the entry and exit points for virtual machines (VM entry/exit).\n\t- Implement logic to intercept sensitive system calls made by the guest and analyze their effects.\n\n4. Guest System Creation\n\t- Allocate memory for the guest and initialize its resources (registers, stack, etc.).\n\n5. Communication\n\t- Use communication channels between the rootkit and the hypervisor to transmit commands or data.\n\n### Persistence\n\nPersistence is a critical capability of any rootkit, enabling it to maintain control over the target system even after a reboot.  \nIn 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.\n\nIt is now useless as it is not our priority to create an APT-tier rootkit, but more research around less seen concepts.\n\n## Setup development environment\n\nMultiple steps needs to be done before compiling our rootkit. The development environment is composed of :\n\n- an Alpine Linux image providing essential tools\n- a custom compiled kernel with Rust activated\n- a QEMU virtual machine accelerated by KVM\n\nStart by cloning the repository and its shallow submodules :\n\n```shell\ngit clone git@github.com:DualHorizon/blackpill.git --recursive --depth 1\n```\n\n### Important dependencies\n\nOn an arch-based distribution :\n\n```shell\nsudo pacman -S qemu-base qemu-desktop docker grub\n```\n\n### Linux Kernel\n\nOn an arch-based Linux distribution, install Rust and other dependencies :\n\n```shell\nsudo pacman -S rust rust-src rust-bindgen\nsudo pacman -S clang lld llvm\n```\n\nThen we'll need Rust sources and bindgen :\n\n```shell\nrustup component add rust-src clippy rustfmt\ncargo install --locked bindgen-cli\n```\n\nMake sure you can start compiling your kernel with Rust by running in folder `linux/` :\n\n```shell\n$ cd blackpill\n$ pushd linux\n$ make LLVM=1 rustavailable\nRust is available!\n$ popd\n```\n\nLaunch the first time setup task which configures and compiles the kernel :\n\n```shell\nmake first-time-setup\n```\n\n\u003e [!IMPORTANT]  \n\u003e If you are asked of customizing options, press Enter each time.\n\n### Rootkit\n\nYou can compile the Rust kernel module (out-of-tree) with :\n\n```shell\nmake\n```\n\nLaunch the VM with :\n\n```shell\nmake vm\n```\n\nInside the VM, you are auto logged in `root`. You can enable the module:\n\n```shell\n$ modprobe blackpill\n# you can check kernel logs with\n$ dmesg\n```\n\n## Usage\n\n### Local Privilege Escalation\n\nOnce the vm started you can use the command above to escalate your privileges:\n\n```shell\nmkdir ImFeelingRootNow_\u003cPID\u003e\n```\n\nReplace `\u003cPID\u003e` with the process id of the process you want to escalate the privilege to.\n\n## C2\n\n### Description\n\nThis simple C2 sends x86-64 opcodes to the infected machine through UDP and receives TCP packets. Its function are now limited to low-level interaction with the machine, but may allow a lot of practical usage with more wrappers.\n\n### Usage\n\nSetup the python client:\n\n```shell\ncd blackpill-c2\npoetry install\npoetry shell\npython client.py\n```\n\nAfter launching the client with your args ([ip] [port]) you should get:\n\n```bash\n$ python client.py 0.0.0.0 1339\nConnected to rootkit!\n```\n\nThen you can use the help command to display available commands:\n\n```python\nblackpill: help\nAvailable Commands\n┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n┃ Command                             ┃ Description                                             ┃\n┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n│ read_virt_memory \u003caddress\u003e          │ Read 4 bytes (32 bits) memory at 'address'              │\n│ write_virt_memory \u003caddress\u003e \u003cvalue\u003e │ Write 4 bytes (32 bits) memory at 'address'             │\n│ launch_userland_binary \u003cpath\u003e       │ Launch a userland binary at 'path'                      │\n│ change_msr \u003cmsr\u003e \u003cvalue\u003e            │ Change the value of a Model Specific Register (MSR)     │\n│ read_phys_memory \u003caddress\u003e \u003cvalue\u003e  │ Read 4 bytes (32 bits) of physical memory at 'address'  │\n│ write_phys_memory \u003caddress\u003e \u003cvalue\u003e │ Write 4 bytes (32 bits) of physical memory at 'address' │\n│ stop_execution                      │ Stop the execution of the guest VM                      │\n│ change_vmcs_field \u003cfield\u003e \u003cvalue\u003e   │ Change a VMCS field to 'value'                          │\n│ help                                │ Show this help message                                  │\n└─────────────────────────────────────┴─────────────────────────────────────────────────────────┘\n```\n\n## Credits\n\nEnvironment setup:\n\n- [Setting Up an Environment for Writing Linux Kernel Modules in Rust - The Linux Foundation](https://www.youtube.com/watch?v=tPs1uRqOnlk)\n- [Kernel config qemu-busybox-min.config patch](https://lore.kernel.org/rust-for-linux/20230609063118.24852-18-amiculas@cisco.com/)\n- [Rust out-of-tree module](https://github.com/Rust-for-Linux/rust-out-of-tree-module)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDualHorizon%2Fblackpill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDualHorizon%2Fblackpill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDualHorizon%2Fblackpill/lists"}