Linux | 基于eBPF的Rootkit攻防利用(一)
2022-10-24 20:38:21 Author: TahirSec(查看原文) 阅读量:179 收藏

LKM 型 Rootkit,一般编写内核模块加载到内核中,挂钩系统调用、虚拟文件系统等,改变内核函数执行流程,实现一系列 Rootkit 功能,比如:

  • 保持对受感染机器的访问

  • 实现各类隐藏功能

  • 创建 root 权限后门

  • 劫持或关闭安全程序

  • 隐私监控与数据窃取

LKM 型 Rootkit 有诸多局限性:
  • 任何小错误都可能导致 kernel panic

  • 内核的任何更新都可能引发新的运行错误

  • 某些环境阻止任意内核模块

这些影响增加了系统的不稳定性,直接暴露攻击行为。希望存在一种更加通用方便快捷的攻击方式,来实现 Rootkit 功能。

具备“内核超能力”的 eBPF 受到安全人员的关注。

1. eBPF超能力

 eBPF 全称扩展伯克利包过滤,最初设计用于快速数据包处理,对系统内核进行观测的技术,一般用于性能、网络、安全的追踪和处理。

eBPF 程序是事件驱动的,并在内核或者应用程序通过某个跟踪点时运行。预定义的跟踪点包括系统调用、函数入口/退出、内核函数跟踪点、Socket、TC、XDP 层的网络事件等。

如果不存在满足特定需求的预定义跟踪点,可以创建内核探针(kprobe)或用户探针(uprobe)在内核或用户应用程序的几乎任何位置挂钩 eBPF。

eBPF 程序的首先使用 C 或 Rust 编写 eBPF 程序,LLVM 编译为字节码,用户态程序,通过一些 eBPF 库,使用 bpf 系统调用将 eBPF 字节码加载到 Linux 内核。

内核 eBPF 验证器验证:

  • 发起 bpf 系统调用的进程是否具有相应权限,要求进程具有相关的 Linux Capabilities(CAP_BPF)或 root 权限;

  • 检查程序是否会导致内核崩溃,例如是否有未初始化的变量,是否有可能导致数组越界、空指针访问的语句;

  • 检查程序是否有限时间执行完。eBPF 只允许有限的循环和跳转,且只允许执行有限的指令条数。

eBPF 程序在完成构建后,挂载到内核的对应事件,如,当某个系统调用产生时,触发内核调用对应的 eBPF 程序。内核 eBPF 程序通过 map 数据结构与用户态程序进行交互,完成相应功能。

Linux 内核模块与 eBPF 之间的对比:

1.1 eBPF环境部署
 $ sudo apt install build-essential git make libelf-dev clang llvm strace tar bpfcc-tools linux-headers-$(uname -r) gcc-multilib  flex  bison libssl-dev -y
1.2 安装源码
 apt-cache search linux-source
 linux-source - Linux kernel source with Ubuntu patches
 linux-source-5.15.0 - Linux kernel source for version 5.15.0 with Ubuntu patches
 
  apt install linux-source-5.15.0
 
 $ ls -hl
 drwxr-xr-x  4 root root 4.0K  519 10:24 linux-source-5.15.0
 lrwxrwxrwx  1 root root   47  5月  5 17:45 linux-source-5.15.0.tar.bz2 -> linux-source-5.15.0/linux-source-5.15.0.tar.bz2
 
 $ tar -jxvf linux-source-5.15.0.tar.bz2
 $ cd linux-source-5.15.0
 
 $ make scripts     # 可选
 $ cp -v /boot/config-$(uname -r) .config # make defconfig 或者 make menuconfig
 $ make headers_install
 $ make M=samples/bpf  # 如果配置出错,可以使用 make oldconfig && make prepare 修复
1.2.1 VMLINUX_BTF 报错处理

如果无法从 vmlinux 生成 vmlinux.h,则 samples/bpf 构建失败。

 samples/bpf/Makefile:369: *** Cannot find a vmlinux for VMLINUX_BTF at any of "  /usr/src/linux-source-5.15.0/vmlinux", build the kernel or set VMLINUX_BTF variable。停止。
 make: *** [Makefile:1875:samples/bpf] 错误 2
两种解决思路,一种直接编译内核得到 vmlinux 内核镜像文件,另一种从 vmlinuz 中提取出 vmlinux 文件,复制到 /usr/src/linux-source-5.15.0。
vmlinuz 是可引导的压缩后的 Linux 内核,文件经过 gzip 和 objcopy(*) 处理,在文件的开头部分有 gzip 解压缩代码,并不是一个正常 gzip 压缩文件。所以无法直接利用 gunzip  或  gzip –dc 直接解压为vmlinux。
所以可以先定位 vmlinuz 中真正的 gzip 压缩文件先提取出来,再进行解压操作得到 vmlinux 文件。
查看 vmlinuz 文件信息,判断 vmlinuz 是 zImage 还是 bzImage 格式

zImage 和 bzImage
zImage 是 vmlinuz 经过 gzip 压缩后的文件,适用于小内核(512KB以内),加载到内存的开始640KB处。
bzimage(not bzizp but big)是 vmlinuz 经过 gzip 压缩后的文件,适用于大内核。
处理zImage格式的vmlinuz
 [[email protected] boot]# od -t x1 -A d vmlinuz | grep "1f 8b 08"
 0013408 ff e0 1f 8b 08 00 ea 80 b9 52 02 03 ec 5b 7f 74
 [[email protected] boot]# dd if=vmlinuz bs=1 skip=0013410 | zcat > vmlinux
 gzip: stdin: decompression OK, trailing garbage ignored
 记录了9195934+0 的读入
 记录了9195934+0 的写出
 9195934字节(9.2 MB)已复制,51.5023 秒,179 kB/秒
skip = 0013410 的计算方式:
skip = 0013408 + 0013408与1f 8b 08 00之间间隔的字节个数,示例间隔2个字节 ff e0,所以 skip 等于 0013408 + 2 = 0013410。
0013408 ff e0 1f 8b 08 00 ea 80 b9 52 02 03 ec 5b 7f 74
两步合并为一个命令:
 dd if=./vmlinuz skip=`grep -a -b -o -m 1 -e $'\x1f\x8b\x08\x00' ./vmlinuz | cut -d: -f 1` bs=1 | zcat > /tmp/vmlinux
处理bzImage格式的vmlinuz
从 bzImage 中提取 vmlinux ,利用 extract-vmlinux 工具 /usr/src/linux-source-5.15.0/scripts/extract-vmlinux
 chmod +x extract-vmlinux
 ./extract-vmlinux vmlinuz > vmlinux
得到解压后的 vmlinux 文件。
$ strings vmlinux | grep sbin
 PATH=/sbin:/usr/sbin:/bin:/usr/bin
 PATH=/sbin:/bin:/usr/sbin:/usr/bin
 /sbin/bridge-stp
 /sbin/modprobe
 /sbin/poweroff
 /sbin/hotplug
最后将从 vmlinuz 中提取出 vmlinux 文件,复制到 /usr/src/linux-source-5.15.0/,重新编译成 BPF 相关示例程序。

2. BPF在攻防中的应用

BPF 很有趣,因为 BPF 程序具有超越普通程序的能力。
  • hook 系统调用和用户空间函数调用

  • 操作用户空间数据结构

  • 修改系统调用返回值

  • 调用 system() 创建新进程(bpftrace内置特性)

  • 某些 BPF 程序可以直接操作硬件设备(如网卡)

  • 针对 BPF 代码的供应链攻击的可能性

  • 配合安全检测工具使用(例如,hook bpf自身)

eBPF 几乎可以实现内核态 Rootkit 所有的隐藏功能,一般的内核模块的挂钩系统调用、虚拟文件系统,eBPF 程序可以使用跟踪点程序类型完成相同功能。针对网络行为,eBPF 程序也可以使用 XDP/TC 等类型完成对数据包的控制,而且流量处理能力更强。

eBPF 利用可以分为两个方面,网络侧和系统侧,分别通过网络类型程序和跟踪点类型程序实现,端口敲门、链路控制、权限提升、隐藏恶意程序行为等。

下面先从网络侧介绍具体的攻防场景。

2.1 网络侧

在网络侧,eBPF 程序挂载到不同层次,可以实现控制链路、敲门和读取数据包内容。

● 控制链路

  • 防火墙前读写包,篡改源和目标 IP 和端口

  • 劫持现有连接

  • 克隆数据包以创建新流量

● 端口敲门

  • 收到某个端口的发起的流量,建立C2连接

● 劫持数据包

  • 可以使用 UProbe 挂钩 OpenSSL 函数,读写 TLS

eBPF 程序挂载到协议层,处理来自特定协议的数据包实现敲门;

挂载到 TC 层,可以控制出口和入口流量,修改数据包;

挂载到 XDP 层,由于在 XDP 处理时,还没有将数据包复制到内核 sk_buffer,可以先于内核其他层处理数据包,尤其是可以在防火墙前读写数据包,篡改数据。但是 XDP 只能控制入口流量。

下图定义了一个 XDP 类型 BPF 程序,此程序对入口流量进行解析判断,通过以太头获取 IP 头, IP 头获取 TCP 头,对目的端口进行判断,如果等于 6666端口,则对以太帧里的 MAC 地址进行替换,如果不是则通过。当做完特定操作后,返回 XDP_DROP 可以丢弃数据包,此时使用 tcpdump 等抓包工具无法获取到此数据包。

2.1.1 BPFtrace 端口敲门

BPFtrace 是一个 BPF 开发的前端工具,可用来创建自定义的 BPF 程序,而不需要处理太多底层技术细节。在 bpftrace 主页中,将之称为 “Linux 系统中的高级跟踪语言 “。

BPFtrace 有一个方便的内置函数可以执行任意系统命令:

//--unsafe选项允许执行不安全的内置函数。bpftrace --unsafe -e 'BEGIN { printf("Hello Offensive BPF!\n");  system("whoami"); }'

攻击利用流程:

  • 攻击者获得了某台主机的特权访问

  • 攻击者安装一个基于 BPFtrace 的后门程序

  • 只要消息来自某个 IP(或源端口),恶意程序就会运行

  • 攻击者用于触发命令后门的 TCP 服务可以为任意类型(HTTP、SSH、MySQL…)

backdoor

  • 加载backdoor后,通过bpftrace挂钩,kretprobe:inet_csk_accep

  • 收到来自攻击者特定IP的特定端口发起的流量

  • 反弹shell建立连接

视频演示 backdoor 攻击流程,rkdetect 对加载到系统的 kprobe 检测,以及使用 bpflist-bpfcc 和 bpftool 取证的整个过程。

2.1.2 boopkit

boopkit 是基于 eBPF 实现的 Rootkit,攻击者可以利用被控端任意的TCP端口服务,远程唤醒后门,具备远程命令执行等能力。
  • 服务端:boopkit,运行在被控端

  • 客户端:boopkit-boop,运行在攻击者使用的控制端

攻击利用流程:

  • 攻击者获得了某台主机的特权访问

  • 攻击者安装一个基于 eBPF 的 TCP 后门

  • 只要消息来自某个 IP(或源端口),恶意程序就会运行

  • 攻击者用于触发命令后门的 TCP 服务可以为任意类型(HTTP、SSH、MySQL…)

boopkit 所需依赖:

 clang
 bpftool Required for libbpf
 xdp-tools Required for libxdp
 llvm
 pcap
 lib32-glibc
xdp-tools、pcap 依赖 libbpf-0.8.0或更高版本,在ubuntu 22.04上,libbpf-dev-0.5.0 版本太低,需要安装更高版本。

boopkit 参数选项:

  • interface -i 参数指定 libpcap 监听的目标网卡。若使用 eBPF XDP 方式,则不需要指定网卡

  • sudo-bypass -s 参数规避sudo用户检测

  • reverse-conn -r 参数是配置参数,是否启用反弹 shell 模式

  • quiet -q 参数是静默模式,不输出日志

    reject -x 参数设置黑名单 IP

boopkit 运行原理

boopkit(服务端)会响应各种网络事件,boopkit-boop(客户端)工具内置了两种敲门机制。
首先,服务端执行 boopkit 程序,跟踪 tcp_bad_csum 数据包校验事件和tcp_receive_reset TCP 重传事件。(pr0be.boop.c

然后,攻击者在客户端执行 boopkit-boop 程序,构造两种敲门方式,boopkit 反弹一个 shell 连接。

两种敲门方式

第一种,发送无效的校验和,boopkit-boop 将通过 SOCK_RAW Socket 向 boopkit 被控端发送一个带有空校验和(Checksum)的 TCP SYN 数据包。(boopkit-boop.c)

第二种, 发送ACK RST包,利用 SOCK_STREAM Socket 针对目标的 TCP 服务(如SSH、Nginx、MySQL等),先正常完成TCP握手后,然后会关闭该 TCP 连接,将重置数据包中的TCP RESET标志位,再重复该过程,发送ACK RST 包进行敲门。(boopkit-boop.c)

敲门成功后服务端主动向客户端 3545 端口,发起连接,客户端返回反弹shell 相关的配置信息,服务端读取后执行反弹 shell 命令,建立新的shell连接。而服务端也挂钩了 getdents 相关的系统调用,将 eBPF 程序自身进程隐藏。(pr0be.safe.c)

SEC("tp/syscalls/sys_enter_getdents64")SEC("tp/syscalls/sys_exit_getdents64")SEC("tp/syscalls/sys_exit_getdents64")
视频演示 boopkit 攻击流程,rkdetect 对系统中 bpf 系统调用的检测,以及使用 bpftrace 和 bpftool 取证的整个过程。
To be Continue ……
reference

https://www.ebpf.top/post/ebpf_c_env/

https://www.ebpf.top/post/offensive-bpf-bpftrace/

https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=ec24704492d8

https://www.cnblogs.com/charlieroro/p/14244276.html

https://www.cnxct.com/ebpf-rootkit-how-boopkit-works/

https://embracethered.com/blog/posts/2021/offensive-bpf-bpftrace/

https://www.brendangregg.com/BPF/bpftrace-cheat-sheet.html

https://github.com/xdp-project/xdp-tools/releases/tag/v1.2.3

https://www.libhunt.com/r/bad-bpf

https://blog.tofile.dev/2021/08/01/bad-bpf.html

https://www.blackhat.com/us-21/briefings/schedule/#with-friends-like-ebpf-who-needs-enemies-23619


文章来源: http://mp.weixin.qq.com/s?__biz=MzkzNjIwMzM5Nw==&mid=2247484832&idx=1&sn=91c18f1795576018e58a8d6be02090c7&chksm=c2a3004af5d4895c211ca7129367a48fd7293d0efeab2c3740c704d565b0f7d5696cb9b8cada#rd
如有侵权请联系:admin#unsafe.sh