drankitagarwal.in

Demystifying eBPF Security: Detecting and Defending Against Kernel-Level Evades

Demystifying eBPF Security: Detecting and Defending Against Kernel-Level Evades

The Rise of eBPF in Modern Security Operations

Over the last few years, Extended Berkeley Packet Filter (eBPF) has transitioned from an obscure Linux kernel technology into the absolute backbone of modern cloud-native security, observability, and networking. By allowing sandboxed programs to run directly inside the Linux kernel without modifying kernel source code or loading external kernel modules, eBPF has empowered security teams with unprecedented, low-overhead visibility into system events, process executions, and network transactions.

Industry-standard tools like Cilium, Tetragon, and Falco rely heavily on eBPF to detect suspicious container behavior and block network threats in real time. However, as defensive security has increasingly consolidated around eBPF, offensive security researchers and advanced threat actors have taken notice. Today, we are witnessing a paradigm shift: attackers are developing highly sophisticated techniques to bypass, blind, or actively exploit eBPF-based security agents. As security professionals, we must understand how these kernel-level evasions work and how to fortify our environments against them.

The Architecture of eBPF: Why It is a Double-Edged Sword

To understand how an attacker can subvert eBPF, we must first understand how it operates. Typically, an eBPF program is compiled from C code into bytecode, verified by the kernel’s in-kernel verifier to ensure safety (preventing infinite loops, out-of-bounds memory access, or system crashes), and then Just-In-Time (JIT) compiled into native machine instructions.

These programs attach to specific hook points in the kernel, such as:

While this architecture grants defenders near-instantaneous visibility, it also provides attackers with a powerful, stealthy environment if they manage to gain root privileges and load malicious eBPF programs. In the hands of an attacker, eBPF can be used to construct next-generation rootkits that hide processes, manipulate system calls, redirect network traffic, and steal credentials directly from memory—all without modifying the traditional /sys/module directory.

The Blind Spots: How Attackers Bypass eBPF Observers

How do modern attackers evade eBPF-based Endpoint Detection and Response (EDR) tools? Generally, offensive techniques fall into three distinct categories: userland agent disruption, map poisoning, and kernel-level hook evasion.

1. Userland Agent Disruption (Blinding the Brain)

An eBPF-based security solution consists of two halves: the kernel-space eBPF program that gathers data, and the user-space daemon (agent) that consumes, processes, and ships those logs to a SIEM. The kernel program communicates with the user-space agent via ring buffers or perf buffers. If an attacker with administrative privileges kills, suspends, or floods the user-space agent, the kernel-space program continues to run, but its telemetry goes nowhere. Alternatively, attackers can use resource exhaustion to spam the ring buffer, causing legitimate security events to be dropped due to buffer overflows.

2. eBPF Map Poisoning and Manipulation

eBPF maps are key-value data structures shared between kernel and user space. Security tools use maps to maintain state, track active processes, or store blocklists. If an attacker gains root access, they can write directly to these maps using the bpf() system call or utilities like bpftool. By injecting false data or deleting entries, they can effectively whitelist their malicious processes, preventing the security agent from triggering alerts on specific process IDs (PIDs) or network connections.

3. Hook Evasion and Helper Exploitation

More sophisticated bypasses target the hooks themselves. For example, if a security tool relies on kprobes attached to system calls (e.g., sys_execve), an attacker can sometimes bypass the hook by invoking lower-level kernel functions directly or utilizing architecture-specific entry points that do not trigger the specific probe. Furthermore, the eBPF helper function bpf_probe_write_user—originally intended for debugging—allows eBPF programs to write to the memory space of a running user-space process. Malicious eBPF programs can abuse this helper to perform on-the-fly code injection, modifying syscall arguments or injecting shellcode into trusted processes.

Hands-On: Detecting Malicious eBPF Activity

To defend against eBPF-based threats, digital forensics and incident response (DFIR) teams must know how to inspect the eBPF subsystem. The primary tool for this task is bpftool, a powerful utility packaged with the Linux kernel.

To list all currently loaded eBPF programs on a system, run the following command:

sudo bpftool prog show

This command outputs the ID, type, name, and helper functions used by each program. When auditing a system, look for anomalies such as:

To inspect active network attachments (such as XDP or Traffic Control filters), use:

sudo bpftool net show

Additionally, you can dump the translated bytecode of a suspect program to analyze its logic and verify that it matches known-good signatures:

sudo bpftool prog dump xlated id <program_id>

Hardening Your Infrastructure Against eBPF Exploits

Detecting malicious eBPF activity after the fact is critical, but preventing unauthorized execution in the first place is the ultimate goal. Implement these three core strategies to harden your Linux infrastructure against eBPF-based threats:

1. Disable Unprivileged eBPF

By default, modern Linux kernels should restrict eBPF loading to privileged users (root or users with CAP_BPF / CAP_SYS_ADMIN capabilities). However, you must explicitly verify this setting. Ensure that unprivileged eBPF is disabled by checking the sysctl configuration:

sysctl kernel.unprivileged_bpf_disabled=1

Persist this setting by writing kernel.unprivileged_bpf_disabled = 1 to your /etc/sysctl.d/99-security.conf file.

2. Enforce eBPF Program Signing

Just as secure boot ensures only signed kernels can load, and kernel module signing prevents untrusted kernel modules from executing, modern Linux kernels support eBPF program signing. By configuring your kernel to only run eBPF programs signed by a trusted internal Certificate Authority (CA), you can completely block attackers—even those with root privileges—from loading arbitrary, unsigned eBPF rootkits.

3. Monitor the bpf() System Call

Every eBPF action, from program loading to map creation, must pass through the bpf() system call. Use auditd, systemd-journald, or external security tools to actively monitor and alert on sys_bpf invocations. A sudden spike in sys_bpf calls from an unexpected binary or directory is a high-fidelity indicator of potential compromise.

Conclusion

eBPF has fundamentally changed the landscape of security observability, offering unparalleled visibility into the depths of the operating system. But as defenders, we must recognize that no technology is a silver bullet. The very capabilities that make eBPF an incredible defensive ally make it an equally potent tool for sophisticated adversaries. By understanding the mechanics of eBPF bypasses, auditing loaded programs with bpftool, and enforcing strict kernel hardening policies, we can ensure this powerful technology remains a shield for our systems rather than a sword for our attackers.

Exit mobile version