1

新型eBPF后门boopkit的原理分析与演示

 1 year ago
source link: https://www.cnxct.com/ebpf-rootkit-how-boopkit-works/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
boopkit-ebpf-backdoor.png

在《聊一聊《Bvp47 美国NSA方程式的顶级后门》中的BPF隐藏信道》一文里,我们讨论了二十年前基于BPF技术后门的功能实现,技术原理等。也展望也在二十年后的今天,eBPF技术加持下,有更多可以被后门利用的技术点,可以造成更大的破坏力。

同时,在《Linux中基于eBPF的恶意利用与检测机制》介绍了eBPF的恶意利用,与防御相关的检测防御机制等。笔者对当下国内IDC对eBPF防御建设的不完善感到忧心,综合国外DefCon等安全峰会中的话题内容,预判未来一段时间,基于eBPF的后门会越来越多,越来越隐秘。

就在一个多月前,笔者看到了一款基于eBPF技术后门Boopkit,上传到https://github.com/kris-nova/boopkit,今天,就跟大家一起来了解一下它的技术原理。

boopkit介绍

boopkit是基于eBPF技术实现的Linux后门rootkit,利用任意开启的TCP端口服务,远程唤醒后门,生成反弹shell,具备远程命令执行等能力。

kris-nova/boopkit

此项目是在2022年3月30日首次创建,至今1个多月,已经有近1000星,在Twitter上也有一定热度,持续传播中。 用户空间的加载器与内核态代码都是纯C编写。 部分脚本使用Makefile、shell等脚本语言。

kris-nova-twitter.jpg

作者 Kris Nóva 是一位女性安全工程师,经常在twitch上直播写代码,有兴趣的同学可以去围观。

krsi-nova-twitch-scaled.jpg

GitHub上Boopkit介绍:

Remote code execution over TCP (SSH, Nginx, Kubernetes, etc)
Network gateway bypass (bad checksums, TCP reset)
Self obfuscation at runtime (eBPF process hiding)

很容易看出,这是后门工具,利用当前服务器开启的任意TCP端口作为通讯隧道,比如SSH、Nginx、Kubernetes等常用服务。利用eBPF技术,在HOOK tracepoint的tcp_bad_csumtcp_receive_reset这两个TCP内核函数,作为敲门、传递信息的机制,进行通讯。并具备进程的自我隐藏等能力。

相比之前《聊一聊BVP47》的SYN窍门,有异曲同工之妙。但多了传送RCE shell等更多利用,当然,也是在高版本eBPF实现的功能。

编译依赖
项目说明中,依赖如下:

clang
bpftool Required for libbpf
xdp-tools Required for libxdp
llvm
pcap
lib32-glibc

笔者环境是ubuntu 22.04的Desktop,内核版本是 5.15的。理论上其他低点的版本有可以运行。

笔者的clangllvm都是12,bpftool在项目编译时不需要,但需要安装libbpf-dev这个开发包,依赖头文件。在ubuntu 22.04上,libbpf-dev0.5.0的版本,版本太低,可以下载libbpf-0.6.1版本,安装使用。

xdp-toolspcap也都是需要开发的头文件,记得安装devel版本的类库。

lib32-glibc包是ArchLinux发行版上的包名字,在其他Linux发行版上一般叫glibc,对应开发库libc6-dev-i386等。

内核依赖
内核版本上项目没说明,理论5.x都行,4.x请自测。但配置上,需要启用tcp_bad_csumtcp_receive_reset两个函数的tracepoint。可以检查/sys/kernel/debug/tracing/events/tcp目录下是否有这两个目录。

tracepoint events

运行依赖
客户端在启动后,需要监听端口,等待后门的反弹shell链接过来。使用的是ncat程序,需要提前安装好。ubuntu上命令sudo apt install ncat

Boopkit后门分为两部分:
服务端:程序名boopkit,运行在被入侵的服务器上。
客户端:程序名boopkit-boop,黑客使用的控制端。

程序名是boopkit,编译好后,会把ebpf的字节码文件写入到/root/.boopkit/目录下,有三个文件:

  1. pr0be.boop.o
  2. pr0be.safe.o
  3. pr0be.xdp.o

pr0be.boop.o用于TCP的网络HOOK,实现敲门以及网络RCE接收。
pr0be.safe.o用于后门进程的自我保护,启动后,在进程列表中隐藏自己。
pr0be.xdp.o截止至2022-05-06,还是空的,没有逻辑。从作者直播中提到,应该是打算用于替换掉libpcap方式的数据包拦截、解析,以及提取RCE,用于更好地隐藏自己。

该程序命令帮助如下:

Boopkit.
Linux rootkit and backdoor. Built using eBPF.

Usage:
boopkit [options]

Options:
-h, help Display help and usage for boopkit.
-i, interface Interface name. lo, eth0, wlan0, etc
-s, sudo-bypass Bypass sudo check. Breaks PID obfuscation.
-r, reverse-conn Attempt a reverse RCE lookup if no payload found.
-q, quiet Disable output.
-x, reject Source addresses to reject triggers from.

interface
-i参数将用于libpcap的网络嗅探的目标网卡,用于提取RCE。若走eBPF XDP方式,则不需要指定网卡,都可以拿到,那么后门的适应性更强。只是作者还没实现。

sudo-bypass
-s参数用于躲避sudo用户检测。

reverse-conn
-r参数是配置参数,当前后门是否启用反弹shell模式。反弹shell模式交互好,但隐蔽性不好。该后门也提供了秘密执行的功能,下文会提到。

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

reject
-x参数算是后门的扩展功能,用于黑名单IP的筛选,意义不大。

前面介绍了后门的参数功能,下面讲下后门对RCE执行的两种方式,以及对应代码实现。

使用libpcap库读取网络通讯包,筛选出黑客的IP,读取TCP的payload信息,匹配特征字符串BOOPKIT_RCE_DELIMITER,读取RCE信息。再调用系统system函数执行。

#define BOOPKIT_RCE_DELIMITER "X*x.x*X"
#define BOOPKIT_RCE_CMD_HALT "X*x.HALT.x*X"

//boopkit.c 
xcap_found = xcaprce(saddrval, rce);
  if (xcap_found == 1) {
    exec(rce);
    bpf_map_delete_elem(fd, &jkey);
    ikey = jkey;
    continue;
  }

// dpi.c

// Search
  for (int i = 0; i < XCAP_BUFFER_SIZE; i++) {
    struct xcap_ip_packet *xpack;
    xpack = snap[i];
    if (!xpack->captured) {
      continue;
    }
    char *xpack_saddr = inet_ntoa(xpack->iph->ip_src);

    char *ret = strstr(search, xpack_saddr);
    if (!ret) {
      continue;  // Filter packets not from our IP address
    }

    // Begin DPI
    unsigned char *packet = xpack->packet;
    char *rce_sub;
    rce_sub = memmem(packet, xpack->header->caplen, BOOPKIT_RCE_DELIMITER,
                     strlen(BOOPKIT_RCE_DELIMITER));
    if (rce_sub != NULL) {
      boopprintf("  -> Found RCE xCap!\n");
      int found;
      found = rce_filter(rce_sub, rce);
      // Flush the snapshot
      xcap_ring_buffer_free(snap);

      // Flush the main ring buffer
      xcap_ring_buffer_free(xcap_ring_buffer);
      xcap_ring_buffer_init(xcap_ring_buffer);
      if (found) {
        return 1;
      } else {
        boopprintf("  XX [FILTER FAILURE] No RCE in xCap!\n");
        return 0;
      }
    }
  }

也可以通过RCE中包含特定字符串,来关停后门。

反弹shell

若后门启用反弹shell模式,则可以让这台boopkit的机器主动向黑客监听端口发起TCP链接。隐蔽性不如上面一种模式,但交互比较好,可以只需不停的读取黑客命令,并调用系统system函数执行。

retval = recvrce(saddrval, rce);
if (retval == 0) {
  exec(rce);
  bpf_map_delete_elem(fd, &jkey);
  ikey = jkey;
  continue;
}

eBPF HOOK

后门一共hook了两类eBPF功能点,TCP与进程列表等几个运行时函数。

eBPF TCP HOOK

pr0be.boop.c
内容比较简单,实现了tcp_bad_csumtcp_receive_reset两个函数HOOK,功能逻辑也比较简单,就是读取TCP包的来源IP,并写入eBPF map,用于存放黑客认证IP。IP将在libpcap网络包读取部分使用。

SEC("tracepoint/tcp/tcp_bad_csum")
SEC("tracepoint/tcp/tcp_receive_reset")

pr0be.safe.c
代码稍微多了一点点,业务功能是实现了当前后门进程的PID隐藏,HOOK了多个函数点:

SEC("tp/syscalls/sys_enter_getdents64")
SEC("tp/syscalls/sys_exit_getdents64")
SEC("tp/syscalls/sys_exit_getdents64")

HOOK点之间,使用多张eBPF Map存储数据,一部分用于内核空间跟用户空间通讯,另外一部分用于多个HOOK点之间通讯。使用bpf_tail_call尾调用实现隐藏逻辑控制。

pr0be.xdp.c

该文件目前是空,前面也提到了,这个应该是作者用于替换libpcap实现网络数据读取的功能,等待实现。

程序名是boopkit-boop,功能是构造畸形或带RCE payload的TCP数据包,发送到服务端,触发服务端内核的tcp_bad_csumtcp_receive_reset函数,对Boopkit后门敲门。

后门程序封装了一个SHELL脚本,启动控制boopkit-boop客户端端更方便。默认启用反弹shell模式,并使用ncat程序监听3545端口,等待被入侵服务器主动连接过来。

boopkit运行原理

how boopkit works

Boop敲门Vectors

Boopkit(服务端)会响应各种网络事件,boopkit-boop(客户端)工具内置了两种敲门机制。

其利用的TCP帧原理如下图:

boopkit-tcp-segment.png

无效的Checksum

boopkit-boop客户端工具将通过SOCK_RAW Socket 向boopkit服务器发送一个带有空校验和的畸形 TCP SYN 数据包。不管这台服务器正在运行什么TCP服务,都会成功敲门,触发eBPF的TCP HOOK。在Linux服务器通吃。

⚠️注意
个别硬件网卡将丢弃所有格式错误的校验和数据包,该工具失效!

发送ACK-RST包

boopkit-boop客户端工具将使用 SOCK_STREAM Socket针对目标的TCP服务(如SSH、Kubernetes、Nginx等)先正常完成TCP握手后,会关闭该TCP链接,以确保这个服务是正常启动的。

之后,再重复该过程,将重置数据包中的TCP RESET标志位,触发服务器上eBPF TCP HOOK。

网络抓包可以抓到敲门的包,但如果用XDP实现,是可以做到读取后,直接XDP_DROP掉,抓包就抓不到了。隐秘性更可怕。

boopkit-tcp-syn-payload.jpg

从图中,可以看到,Checksum的值是0,且后面的TCP Segment已经被改成不合法的,无法解析的包。RCE也被放置在payload中。(两头加了BOOPKIT_RCE_DELIMITER标记)

后门不监听端口,隐藏进程,普通工具查不出来。

RCE执行时,会有记录,但进程的父ID查不出来。 top命令却能直接看到,也能直接kill掉,隐藏的不够好。

boopkit-top.jpg

基于eBPF的特征

GitHub上,笔者开源了一个基于eBPF实现的HIDS入侵检测系统ehids-agent DEMO,具备基本的BPF Call调用检测,可以来测试一下能否发现。

ehids-logo.png

为了减少干扰信息,笔者这里只开启了eHIDS的bpf call monitor模块。

cfc4n@vm-desktop:~/project/ehids-agent$ sudo ./bin/ehids-agent 
[sudo] password for cfc4n: 
2022/05/07 00:21:53 https://github.com/ehids/ehids-agent
2022/05/07 00:21:53 process pid: 69409
2022/05/07 00:21:53 start to run EBPFProbeBPFCall module
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:1, Cmd:BPF_PROG_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop
2022/05/07 00:21:59 probeName:EBPFProbeBPFCall, probeTpye:tracepoint, BPFCALL EVENT CPU:0, Cmd:BPF_BTF_LOAD, PID:69416, UID:0, Comm:boopkit, cmdline:./boopkit -i ens33, utsName:vm-desktop

可以看到,能精准地监控到调用的BPF指令,进程ID,进程名,命令行参数等。

该后门,在进程PID隐藏上做了实现,但在bpf的行为特征上,目前还没有实现。可以用bpftool等常规工具来检查它。

root@vm-desktop:~# bpftool prog show
216: tracepoint  name handle_getdents  tag d5fabe9da09eec5e  gpl
    loaded_at 2022-05-07T00:25:16+0800  uid 0
    xlated 144B  jited 93B  memlock 4096B  map_ids 135,129
    btf_id 180
218: tracepoint  name handle_getdents  tag d197d702eb020291  gpl
    loaded_at 2022-05-07T00:25:16+0800  uid 0
    xlated 1216B  jited 841B  memlock 4096B  map_ids 129,130,135,132,131
    btf_id 180
219: tracepoint  name handle_getdents  tag e938383ee7761b31  gpl
    loaded_at 2022-05-07T00:25:16+0800  uid 0
    xlated 544B  jited 310B  memlock 4096B  map_ids 132,133,135
    btf_id 180
222: tracepoint  name tcp_bad_csum  tag 82cc666e25685b71  gpl
    loaded_at 2022-05-07T00:25:16+0800  uid 0
    xlated 744B  jited 404B  memlock 4096B  map_ids 138
    btf_id 181
223: tracepoint  name tcp_receive_res  tag c25930e6076718fc  gpl
    loaded_at 2022-05-07T00:25:16+0800  uid 0
    xlated 416B  jited 227B  memlock 4096B  map_ids 138
    btf_id 181

如上,一样的方法。

root@vm-desktop:~# bpftool map show
129: hash  name map_buffs  flags 0x0
    key 8B  value 8B  max_entries 8192  memlock 131072B
    btf_id 180
130: hash  name map_bytes_read  flags 0x0
    key 8B  value 4B  max_entries 8192  memlock 131072B
    btf_id 180
131: prog_array  name map_prog_array  flags 0x0
    key 4B  value 4B  max_entries 5  memlock 4096B
    owner_prog_type tracepoint  owner jited
    btf_id 180
132: hash  name map_to_patch  flags 0x0
    key 8B  value 8B  max_entries 8192  memlock 131072B
    btf_id 180
133: ringbuf  name rb  flags 0x0
    key 0B  value 0B  max_entries 8192  memlock 0B
135: array  name pr0be_sa.rodata  flags 0x480
    key 4B  value 24B  max_entries 1  memlock 4096B
    btf_id 180  frozen
136: array  name pr0be_sa.bss  flags 0x400
    key 4B  value 20B  max_entries 1  memlock 4096B
    btf_id 180
138: hash  name event  flags 0x0
    key 4B  value 32B  max_entries 8192  memlock 327680B
    btf_id 181
139: array  name pr0be.bss  flags 0x400
    key 4B  value 20B  max_entries 1  memlock 4096B
    btf_id 181

可参考 《Linux中基于eBPF的恶意利用与检测机制》一文。

当前后门发往外部的TCP通讯是可监控,对网络捕获的实现是libpcap库,特征比较明显,而这个程序作者不停改进中。业界中,有人分享过更隐秘的技术方式,比如在内核态,复用业务的网络包,更改内容发数据包给黑客。躲避了用户态的检查。

这后门虽然不完美,但这只是GitHub开源社区的现状,相信在黑市里,早有隐秘性笔者高很多的后门在使用。笔者再次呼吁,务必加快对eBPF恶意利用的防御检测体系建设。

微信公众号

wechat-white-search-no-alpha-800x376.png

回复boopkit获取该文章链接。

CFC4N的博客 由 CFC4N 创作,采用 知识共享 署名-非商业性使用-相同方式共享(3.0未本地化版本)许可协议进行许可。基于https://www.cnxct.com上的作品创作。转载请注明转自:新型eBPF后门boopkit的原理分析与演示


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK