使用 eBPF/XDP 实现 Shell 命令监控方案
方案概述
通过 eBPF 技术监控系统上执行的所有 shell 命令,可以实现以下功能:
- 实时捕获所有用户执行的命令
- 记录命令执行上下文(用户、PID、时间等)
- 检测可疑命令模式
- 与安全系统集成实现实时阻断
实现方法
1. 使用 eBPF 的 tracepoint/syscall 挂钩
// cmd_monitor.c - eBPF 程序监控 execve 系统调用
#include <linux/bpf.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/version.h>
// 定义用于存储命令数据的结构
struct command_event {
char comm[16]; // 进程名
char cmdline[256]; // 完整命令
uid_t uid; // 用户ID
pid_t pid; // 进程ID
};
// 定义eBPF map用于用户空间读取数据
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(u32));
} events SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_execve")
int trace_execve_entry(struct trace_event_raw_sys_enter* ctx) {
struct command_event event = {};
// 获取进程信息
event.pid = bpf_get_current_pid_tgid() >> 32;
event.uid = bpf_get_current_uid_gid();
bpf_get_current_comm(&event.comm, sizeof(event.comm));
// 从execve参数获取命令行
char** cmdline = (char**)ctx->args[1];
bpf_probe_read_user_str(event.cmdline, sizeof(event.cmdline), cmdline[0]);
// 发送事件到用户空间
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
return 0;
}
char _license[] SEC("license") = "GPL";
2. 用户空间收集程序 (Python)
#!/usr/bin/env python3
from bcc import BPF
import ctypes
import time
# 定义与eBPF程序中相同的结构
class CommandEvent(ctypes.Structure):
_fields_ = [
("comm", ctypes.c_char * 16),
("cmdline", ctypes.c_char * 256),
("uid", ctypes.c_uint32),
("pid", ctypes.c_uint32),
]
# 加载eBPF程序
b = BPF(src_file="cmd_monitor.c")
b.attach_tracepoint(tp="syscalls:sys_enter_execve", fn_name="trace_execve_entry")
# 处理事件回调
def print_event(cpu, data, size):
event = ctypes.cast(data, ctypes.POINTER(CommandEvent)).contents
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] UID:{event.uid} PID:{event.pid} CMD:{event.cmdline.decode()}")
# 设置perf缓冲区
b["events"].open_perf_buffer(print_event)
print("Monitoring shell commands... Ctrl+C to exit")
# 主循环
while True:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
exit()
3. 高级监控功能扩展
3.1 命令阻断功能
// 在eBPF程序中添加安全检测逻辑
SEC("tracepoint/syscalls/sys_enter_execve")
int trace_execve_entry(struct trace_event_raw_sys_enter* ctx) {
// ... 原有代码 ...
// 危险命令检测
if (is_dangerous_command(event.cmdline)) {
// 返回错误码阻止命令执行
return -EPERM;
}
// ... 原有代码 ...
}
// 危险命令检测函数
static __always_inline bool is_dangerous_command(const char* cmd) {
// 这里可以添加更复杂的检测逻辑
return bpf_strstr(cmd, "rm -rf") != 0 ||
bpf_strstr(cmd, "chmod 777") != 0;
}
3.2 上下文信息增强
// 获取父进程信息
struct parent_info {
char comm[16];
pid_t ppid;
};
// 在原有事件结构中添加父进程信息
struct command_event {
// ... 原有字段 ...
struct parent_info parent;
};
// 在tracepoint处理函数中获取父进程信息
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
struct parent_info parent = {};
parent.ppid = BPF_CORE_READ(task, real_parent, pid);
bpf_probe_read_kernel_str(&parent.comm, sizeof(parent.comm),
BPF_CORE_READ(task, real_parent, comm));
部署方案
1. 系统要求
- Linux 内核 4.9+
- 启用 eBPF 相关内核配置
- 需要 CAP_BPF 能力或 root 权限
2. 生产环境增强
2.1 与日志系统集成
# 修改print_event函数将日志发送到ELK/Splunk等系统
def print_event(cpu, data, size):
event = ctypes.cast(data, ctypes.POINTER(CommandEvent)).contents
log_entry = {
"timestamp": datetime.now().isoformat(),
"user": event.uid,
"pid": event.pid,
"command": event.cmdline.decode(),
"process": event.comm.decode(),
"parent_pid": event.parent.ppid,
"parent_process": event.parent.comm.decode()
}
send_to_log_system(log_entry) # 实现你的日志发送逻辑
2.2 性能优化
// 使用eBPF map缓存常用检测结果
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 1024);
__type(key, u32); // UID
__type(value, u64); // 上次执行时间
} user_last_exec SEC(".maps");
// 在检测函数中添加速率限制
if (bpf_map_lookup_elem(&user_last_exec, &event.uid)) {
u64 last_time = *lookup;
if (bpf_ktime_get_ns() - last_time < 100000000) { // 1秒内
return -EACCES; // 限制命令执行频率
}
}
安全注意事项
-
权限控制:
- 监控程序本身需要高权限,需妥善保护
- 日志存储需要加密和访问控制
-
隐私考虑:
- 遵守当地法律法规
- 对敏感命令进行脱敏处理
-
防篡改:
- 对eBPF程序进行签名验证
- 监控程序完整性
替代方案比较
方法 | 优点 | 缺点 |
---|---|---|
eBPF | 高性能、内核级可见性 | 需要较新内核 |
Auditd | 系统原生支持 | 性能开销大 |
Ptrace | 灵活性强 | 高开销、易被检测 |
总结
这个eBPF/XDP实现的shell命令监控方案具有以下特点:
- 高性能:在内核层面处理,几乎不影响系统性能
- 全面性:可以捕获所有用户的shell命令执行
- 可扩展:易于添加更复杂的安全检测逻辑
- 实时性:能够实现实时阻断危险命令
适合需要高级命令监控和安全审计的生产环境使用。