TripleCross – A Linux eBPF Rootkit With A Backdoor, C2, Library Injection, Execution Hijacking, Persistence And Stealth Capabilities.
TripleCross is a Linux eBPF rootkit that demonstrates the offensive capabilities of the eBPF technology.
TripleCross is inspired by previous implant designs in this area, notably the works of Jeff Dileo at DEFCON 27
The raw sockets library RawTCP_Lib used for rootkit transmissions is of my authorship and has
Therefore in order to check from eBPF that an address in the stack is the return address that will lead us to the correct GOT, we must check that it is the return address of the PLT stub that uses the GOT address that jumps to the glibc function making the system call we hooked from eBPF.
Two techniques for finding the return address have been incorporated:
- With sys_timerfd_settime, the eBPF program scans forward in the scan using the syscall arguments.
- With sys_openat, the eBPF program scans uses the data at tracepoints’ pt_regs struct for scanning the return address.
Locating key functions for shellcode
The shellcode must be generated dynamically to bypass ASLR and PIE, which change the address of functions such as dlopen() on each program execution.
Injecting shellcode in a code cave
A code cave can be found by
Overwriting the GOT section
Depending on whether Partial or Full RELRO are active on the executable, the eBPF program overwrites the GOT section directly or with the /proc filesystem.
Waiting for the next system call
When the next syscall is issued in the hijacked program, the PLT section uses the modified GOT section, hijacking the flow of execution which gets redirected to the shellcode at the code cave. The shellcode is prepared to keep the program from crashing, and calls the malicious library (src/helpers/lib_injection.so). This library issues a fork() and spawns a reverse shell with the attacker machine. Afterwards the flow of execution is restored.
Backdoor and C2
The backdoor works out of the box without any configuration needed. The backdoor can be controlled remotely using the rootkit client program:
CLIENT ARGUMENTS | ACTION DESCRIPTION |
---|---|
./injector -c <Victim IP> | Spawns a plaintext pseudo-shell by using the execution hijacking module |
./injector -e <Victim IP> | Spawns an encrypted pseudo-shell by commanding the backdoor with a pattern-based trigger |
./injector -s <Victim IP> | Spawns an encrypted pseudo-shell by commanding the backdoor with a multi-packet trigger (of both types) |
./injector -p <Victim IP> | Spawns a phantom shell by commanding the backdoor with a pattern-based trigger |
./injector -a <Victim IP> | Orders the rootkit to activate all eBPF programs |
./injector -u <Victim IP> | Orders the rootkit to detach all of its eBPF programs |
./injector -S <Victim IP> | Showcases how the backdoor can hide a message from the kernel (Simple PoC) |
./injector -h | Displays help |
Backdoor triggers
Actions are sent to the backdoor using backdoor triggers, which indicate the backdoor the action to execute depending on the value of the attribute K3:
K3 VALUE | ACTION |
---|---|
0x1F29 | Request to start an encrypted pseudo-shell connection |
0x4E14 | Request to start a phantom shell connection |
0x1D25 | Request to load and attach all rootkit eBPF programs |
0x1D24 | Request to detach all rootkit eBPF programs (except the backdoor’s) |
Pattern-based trigger
This trigger hides the command and client information so that it can be recognized by the backdoor, but at the same time seems random enough for an external network supervisor. It is based on the trigger used by the recently discovered NSA rootkit
Multi-packet trigger
This trigger consists of multiple TCP packets on which the backdoor payload is hidden in the packet headers. This design is based on the CIA
A rolling XOR is then computed over the above payload and it is divided into multiple parts, depending on the mode selected by the rootkit client. TripleCross supports payloads hidden on the TCP sequence number:
And on the TCP source port:
Backdoor pseudo-shells
The client can establish rootkit pseudo-shells, a special rootkit-to-rootkit client connection which simulates a shell program, enabling the attacker to execute Linux commands remotely and get the results as if it was executing them directly in the infected machine. Multiple pseudo-shells are incorporated in our rootkit:
Plaintext pseudo-shell
This shell is generated after a successful run of the execution hijacking module, which will execute a malicious file that establishes a connection with the rootkit client as follows:
Encrypted pseudo-shell
An encrypted pseudo-shell can be requested by the rootkit client at any time, consisting of a TLS connection between the rootkit and the rootkit client. Inside the encrypted connection, a transmission protocol is followed to communicate commands and information, similar to that in plaintext pseudo-shells.
Spawning an encrypted pseudo-shell requires the backdoor to listen for triggers, which accepts either pattern-based triggers or both types of multi-packet trigger:
Phantom shell
A phantom shell uses a combination of XDP and TC programs to overcome eBPF limitations at the network, specifically that it cannot generate new packets. For this, the backdoor modifies existing traffic, overwriting the payload with the data of the C2 transmission. The original packets are not lost since TCP retransmissions send the original packet (without modifications) again after a short time.
The following protocol illustrates the traffic during the execution of a command using a phantom shell:
A phantom shell is requested by the rootkit client which issues a command to be executed by the backdoor:
After the infected machine sends any TCP packet, the backdoor overwrites it and the client shows the response:
Execution hijacking module
In principle, an eBPF program cannot start the execution of a program by itself. This module shows how a malicious rootkit may take advantage of benign programs in order to execute malicious code at the user space. This module achieves two goals:
- Execute a malicious user program taking advantage of other program’s execution.
- Be transparent to the user space, that is, if we hijack the execution of a program so that another is run, the original program should be executed too with the least delay.
This module works by hijacking the sys_execve() syscall, modifying its arguments so that a malicious program (src/helpers/execve_hijack.c) is run instead. This
The arguments of the original sys_execve() call are modified in such a way that the original arguments are not lost (using argv[0]) so that the original program can be executed after the malicious one:
We have incorporated a sample test program (src/helpers/simple_execve.c) for testing the execution hijacking module. The module can also hijack any call in the system, depending on the configuration:
FILENAME | CONSTANT | DESCRIPTION |
---|---|---|
src/common/constants.h | PATH_EXECUTION_HIJACK_PROGRAM | Location of the malicious program to be executed upon succeeding to execute a sys_execve call |
src/common/constants.h | EXEC_HIJACK_ACTIVE | Deactivate (0) or activate (1) the execution hijacking module |
src/common/constants.h | TASK_COMM_RESTRICT_HIJACK_ACTIVE | Hijack any sys_execve call (0) or only those indicated in TASK_COMM_NAME_RESTRICT_HIJACK (1) |
src/common/constants.h | TASK_COMM_NAME_RESTRICT_HIJACK | Name of the program from which to hijack sys_execve calls |
After a successful hijack, the module will stop itself. The malicious program execve_hijack will listen for requests of a plaintext pseudo-shell from the rootkit client.
Rootkit persistence
After the infected machine is rebooted, all eBPF programs will be unloaded from the kernel and the userland rootkit program will be killed. Moreover, even if the rootkit could be run again automatically, it would no longer enjoy the root privileges needed for attaching the eBPF programs again. The rootkit persistence module aims to tackle these two challenges:
- Execute the rootkit automatically and without user interaction after a machine reboot event.
- Once the rootkit has acquired root privileges the first time it is executed in the machine, it must keep them even after a reboot.
TripleCross uses two secret files, created under cron.d and sudoers.d, to implement this functionality. These entries ensure that the rootkit is loaded automatically and with full privilege after a reboot. These files are created and managed by the deployer.sh script:
The script contains two constants that must be configured for the user to infect on the target system:
SCRIPT | CONSTANT | DESCRIPTION |
---|---|---|
src/helpers/deployer.sh | CRON_PERSIST | Cron job to execute after reboot |
src/helpers/deployer.sh | SUDO_PERSIST | Sudo entry to grant password-less privileges |
Rootkit stealth
The persistence module is based on creating additional files, but they may get eventually found by the system owner or by some software tool, so there exists a risk on leaving them in the system. Additionally, the rootkit files will need to be stored at some location, in which they may get discovered.
Taking the above into account, the stealth module provides the following functionality:
- Hide a directory completely from the user (so that we can hide all rootkit files inside).
- Hide specific files in a directory (we need to hide the persistence files, but we cannot hide the sudoers.d or cron.d directories completely, since they belong to the normal system functioning).
The files and directories hidden by the rootkit can be customized by the following configuration constants:
FILENAME | CONSTANT | DESCRIPTION |
---|---|---|
src/common/constants.h | SECRET_DIRECTORY_NAME_HIDE | Name of directory to hide |
src/common/constants.h | SECRET_FILE_PERSISTENCE_NAME | Name of the file to hide |
By default, TripleCross will hide any files called “ebpfbackdoor” and a directory named “SECRETDIR“. This module is activated automatically after the rootkit installation.
The technique used for achieving this functionality consists of tampering with the arguments of the sys_getdents() system call:
License
The TripleCross rootkit and the rootkit client are licensed under the GPLv3 license. See LICENSE.
The RawTCP_Lib library is licensed under the MIT license.
The original thesis document and included figures are released under Creative Commons BY-NC-ND 4.0.
Footnotes
-
J. Dileo. Evil eBPF: Practical Abuses of an In-Kernel Bytecode Runtime. DEFCON 27. slides
-
P. Hogan. Warping Reality: Creating and Countering the Next Generation of Linux Rootkits using eBPF. DEFCON 27. presentation
-
G. Fournier and S. Afchain. eBPF, I thought we were friends! DEFCON 29. slides
-
Kris Nóva. Boopkit. github
If you like the site, please consider joining the telegram channel or supporting us on Patreon using the button below.