使用 eBPF/XDP 实现 Shell 命令监控方案

使用 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; // 限制命令执行频率
    }
}

安全注意事项

  1. 权限控制:

    • 监控程序本身需要高权限,需妥善保护
    • 日志存储需要加密和访问控制
  2. 隐私考虑:

    • 遵守当地法律法规
    • 对敏感命令进行脱敏处理
  3. 防篡改:

    • 对eBPF程序进行签名验证
    • 监控程序完整性

替代方案比较

方法优点缺点
eBPF高性能、内核级可见性需要较新内核
Auditd系统原生支持性能开销大
Ptrace灵活性强高开销、易被检测

总结

这个eBPF/XDP实现的shell命令监控方案具有以下特点:

  1. 高性能:在内核层面处理,几乎不影响系统性能
  2. 全面性:可以捕获所有用户的shell命令执行
  3. 可扩展:易于添加更复杂的安全检测逻辑
  4. 实时性:能够实现实时阻断危险命令

适合需要高级命令监控和安全审计的生产环境使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值