eBPF惊艳的操作:命令审计和录屏
2022-12-11 08:2:37 Author: 奶牛安全(查看原文) 阅读量:29 收藏

本文提及所有代码都是在https://github.com/iovisor/bcc/tree/master/tools

很多时候,生产环境是需要对操作人的操作进行审计,防止有人做删库跑路这种脑残且毫无技术含量的行为。所以,就需要一些技术来跟踪用户的操作。

要学点有技术含量的,请学一下恶意软件相关技术吧。

用户操作的跟踪,就是跟踪用户名称,命令,以及命令的结果。

进程启动实时跟踪

命令在Linux下,大多数时候都是进程来表示。所以,很自然,就需要监控进程实时启动了。

目前有很多技术可以做到实时进程启动的监控。如audit和内核驱动。

audit是在系统调用上挂钩子,是静态的钩子,因为内核本身就提供了这样的钩子,只要打开就行。

内核驱动也是挂钩子,它是使用kprobekretprobe两种机制来挂钩,是动态的钩子,也就是原来不存在,现在它挂上了。

那么,eBPF能不能做到呢?当然可以了。它可以支持kprobekretprobe的。

而它的工具bcc就有专门的脚本做得这事。

[email protected]:~/Downloads$cat /etc/passwd>/dev/null
[email protected]:~/Downloads$cat /etc/user>/dev/null
cat: /etc/user: No such file or directory
[email protected]:~/Downloads$ps aux>/dev/null
[email protected]:~/Downloads$echo "hello"
hello
[email protected]:~/Downloads$cd 
[email protected]:~$ld
ld: no input files

另外一个屏幕在这些命令执行之前运行

[email protected]:/usr/share/bcc/tools$sudo ./execsnoop -U -T -x
TIME     UID   PCOMM            PID     PPID    RET ARGS
13:07:18 1000  cat              5458    5135      0 /usr/bin/cat /etc/passwd
13:07:22 1000  cat              5459    5135      0 /usr/bin/cat /etc/user
13:07:30 1000  ps               5462    5135      0 /usr/bin/ps aux
13:08:13 1000  ld               5464    5135      0 /usr/bin/ld

可以看到是, 上面例子捕获到用户ID为1000的用户使用了cat,psld三个命令,连cat命令操作哪些文件也显示出来。

但有一个问题,像echocd这些shell内置的命令,却捕获不到。

如果我们看一下execsnoop这个脚本,可以看到这几行

b = BPF(text=bpf_text)
execve_fnname = b.get_syscall_fnname("execve")
b.attach_kprobe(event=execve_fnname, fn_name="syscall__execve")
b.attach_kretprobe(event=execve_fnname, fn_name="do_ret_sys_execve")

它是使用kprobekretprobe来对execve进行挂钩来跟踪实时进程启动的。

shell内置命令跟踪

那么,怎么获取那些shell内置命令的操作记录?

非常土的方法是读取用户目录下的.bash_history文件,当然不同的shell有不同的名称。

但这种手段,不是实时的,而且同时多个会话拼接在一起,往往会丢失一些记录。

如果是需要实时,怎么办?以往在某大厂时,是直接魔改bash,这样确实能够采集得到。但会遇到版本兼容和稳定性的问题,经常出问题被业务部门各种操。

eBPF呢,它对用户态也有类似kprobe/kretprobe之类的机制,叫uprobe/uretprobe,基本能够对用户态函数挂钩,能够以非侵入式的方式跟踪用户操作记录。

bcc的工具里,有一个叫bashreadline,就是使用uprobe机制,用来捕获bash里任何的命令输入。

在第二个屏幕输入:

[email protected]:~/Downloads$echo "hello"
hello
[email protected]:~/Downloads$alias lls='ls -l'
[email protected]:~/Downloads$cd
[email protected]:~$cd -
/home/nainiu/Downloads
[email protected]:~/Downloads$export DOFU="sfjsk"
[email protected]:~/Downloads$ps aux>/dev/null

在这之前,在第一屏幕先运行bashreadline

[email protected]:/usr/share/bcc/tools$sudo ./bashreadline
TIME      PID     COMMAND
13:20:12  5135    echo "hello"
13:22:07  5135    alias lls='ls -l'
13:23:26  5135    cd
13:23:29  5135    cd -
13:23:56  5135    export DOFU="sfjsk"
13:24:36  5135    ps aux>/dev/null

可以看出来,这个工具能够完美把bash上所有命令,包括外在的还是内置都显示出来。这里唯一不足,是没办法知道哪个用户。不过,要添加一下代码,也是非常容易做到的。

这里看一下它的代码,

b = BPF(text=bpf_text)
b.attach_uretprobe(name=name, sym="readline", fn_name="printret")

就是用自定义的函数printretreadline函数挂了一个uretprobe的钩子。

录屏

很多时候,不光是想获取用户执行命令的记录,还想获取结果,也就是所谓的录屏。

这个操作,以往是一般改造logindsshd。一个本地登录,启动各种shell的守护进程,一个是远程登录的。

改造方式有两种:

  • 对程序代码本身进行修改,要自己维护安装包,确保监控的机器一定要使用修改的代码,要每个版本都兼容。这种方式成本高,稳定性很差。
  • 编写一个PAM模块,让logindsshd启动时,都加载到,在这个模块里进行录屏。这种方式呢,对兼容性要求没上一种那么高,稳定性也好一些,毕竟启动PAM模块时,会启动一个子进程处理,如果出现问题,也只是这个子进程会崩溃。

但无论如何,这两种方法都是侵入式修改。我以前都用过,也背过堪称三座大山的锅,所以,对于这两种方式,都是避而远之。

eBPF却可以对tty_write之类的内核函数进行kprobe/kretprobe挂钩,从而实现录屏功能。

bcc里就有一个ttysnoop的工具,使用上面机制进行录屏功能。

在第二屏幕执行:

[email protected]:~/Downloads$ls
VMwareTools-10.3.10-13959562.tar.gz  vmware-tools-distrib
[email protected]:~/Downloads$ps 
    PID TTY          TIME CMD
   5135 pts/1    00:00:00 bash
   6727 pts/1    00:00:00 ps
[email protected]:~/Downloads$date
2022年 12月 10日 星期六 16:05:18 CST
[email protected]:~/Downloads$time ls
VMwareTools-10.3.10-13959562.tar.gz  vmware-tools-distrib

real 0m0.003s
user 0m0.000s
sys 0m0.003s

在这之前,在第一屏幕执行sudo ./ttysnoop 1 -C:

在这里第二屏幕是在/dev/pts/1,所以参数是1

[email protected]:/usr/share/bcc/tools$sudo ./ttysnoop 1 -C
ls
VMwareTools-10.3.10-13959562.tar.gz  vmware-tools-distrib
[email protected]:~/Downloads$ps 
    PID TTY          TIME CMD
   5135 pts/1    00:00:00 bash
   6727 pts/1    00:00:00 ps
[email protected]:~/Downloads$date
2022年 12月 10日 星期六 16:05:18 CST
[email protected]:~/Downloads$time ls
VMwareTools-10.3.10-13959562.tar.gz  vmware-tools-distrib

real 0m0.003s
user 0m0.000s
sys 0m0.003s
[email protected]:~/Downloads$

请注意第一行命令提示符和后面那些,是不是不一样了?

看一下ttysnoop的代码:

#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 11)
int kprobe__tty_write(struct pt_regs *ctx, struct file *file,
    const char __user *buf, size_t count)

{
    if (file->f_inode->i_ino != PTS)
        return 0;

    return do_tty_write(ctx, buf, count);
}
#else
KFUNC_PROBE(tty_write, struct kiocb *iocb, struct iov_iter *from)
{
    const char __user *buf;
    const struct kvec *kvec;
    size_t count;

    if (iocb->ki_filp->f_inode->i_ino != PTS)
        return 0;
/**
 * commit 8cd54c1c8480 iov_iter: separate direction from flavour 
 * `type` is represented by iter_type and data_source seperately
 */

#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
    if (from->type != (ITER_IOVEC + WRITE))
        return 0;
#else
    if (from->iter_type != ITER_IOVEC)
        return 0;
    if (from->data_source != WRITE)
        return 0;
#endif

    kvec  = from->kvec;
    buf   = kvec->iov_base;
    count = kvec->iov_len;

    return do_tty_write(ctx, kvec->iov_base, kvec->iov_len);
}
#endif

可见,它确实是使用了kprobetty_write进行挂钩来实现这个效果。

滥用

bcc这三个工具,其实都是能够扩展的。如果黑客攻陷了一台主机,这台主机也能够运行eBPF,他就可以通过类似工具来嗅探到这台主机(包括主机上运行的容器)任何操作,从而获取相关业务系统的用户密码或者横向移动。

那么,应该怎么防治呢?

bcc有个工具叫bpflist,能够获取当前系统运行的eBPF实例。

[email protected]:/usr/share/bcc/tools$ sudo ./bpflist -vv
open kprobes:

open uprobes:

PID    COMM             TYPE  COUNT
1      systemd          prog  18
6768   python           map   2
6768   python           prog  1
[email protected]:/usr/share/bcc/tools$ ps aux|grep 6768
root        6768  1.4  3.4 179796 137976 pts/3   S+   16:18   0:02 python ./ttysnoop 1 -C

可以看到当前系统运行了两个程序,systemdttysnoop

至于bpflist的实现,大家自己看代码,非常简单的,就是读/sys/kernel/debug/tracing/*_events的结果。

暗号:d9510


文章来源: http://mp.weixin.qq.com/s?__biz=MzU4NjY0NTExNA==&mid=2247487747&idx=1&sn=3e200478203415989f4973c9456ee2eb&chksm=fdf97a16ca8ef30055b77babf1ede6cfc9acdcb56afa59291730e961f0e5fc6c378d2591967c#rd
如有侵权请联系:admin#unsafe.sh