初探eBPF

渗透技巧 2年前 (2022) admin
959 0 0


初探eBPF

前言

由Linux基金会维护的ebpf.io网站[1]写到:

eBPF是Linux中的一项革命性技术,可以在操作系统内核中运行沙箱程序。它可以在无需修改内核代码或加载内核模块的条件下安全有效地扩展内核能力。

那么,如此神奇的技术是如何实现的呢?它具体可以做什么?以及我们如何使用它?不急,请允许我先讲一点点历史。

BPF

BPF(Berkeley Packet Filter),译为伯克利包过滤器,可以说是eBPF的前身。在1992年一篇名为《The BSD Packet Filter:A New Architecture for User-level Packet Capture》[2]的论文中讲述了这种新型包过滤技术。BPF作为类Unix系统上数据链路层的一种原始接口,它在内核中部署Packet Filter,对网络数据包进行过滤后再拷贝到用户态。这种处理方法在当时有别于主流,极大程度上降低了拷贝到用户态数据包的数量。BPF凭借其重新设计的基于CPU寄存器的包过滤机制,比当时基于内存堆栈的CMU/Stanford Packet Filter快1.5~20倍。以及,BPF实现的非共享缓冲区模型比Sun的NIT技术快10~100倍。BPF在1997年被引入Linux 2.1.75,定名为LSF(Linux Socket Filter)[3]。

eBPF

eBPF(extended Berkeley Packet Filter)最初目的是优化处理网络过滤器内部指令集。然而经过重新设计,eBPF已不仅局限于网络栈。2014年起,eBPF逐渐发展成为一个通用的执行引擎,更是将能力拓展到用户空间。与内核模块不同的是,eBPF允许使用者从用户态向内核态注入代码,而不用重新编译内核或加载内核模块。eBPF在Linux 3.18内核中被引入,此后原来的BPF技术被称作cBPF(classic BPF),现在BPF多指代eBPF技术。需要注意的是,eBPF对Linux内核做到了向前兼容,低版本内核升级到最新子版本也可以使用部分eBPF功能。例如,后文实验就是在3.10.0-1160.45.1内核版本下完成。

初探eBPF

在如此强大的扩展能力下,eBPF如何保障内核的安全与稳定也是重点问题。换句话说,这种稳定性与安全性的保障意味着内核中的eBPF会给予用户提交程序诸多限制。当然,随着技术的演进,这些限制亦是在逐步放宽。

原理

初探eBPF

eBPF主要分为用户空间程序与内核程序两大部分。

在用户空间,程序被编译成eBPF可接受的字节码并提交到内核,以及负责读取内核回传的消息事件或统计信息。eBPF提供了两种内核态与用户态传递数据的方式,内核态可以将自定义perf_event消息事件发往用户态,或用户态通过文件描述符读写存储在内核中的k/v Map数据。

在内核空间,为了稳定与安全,eBPF接收的字节码首先会交给Verifier进行安全验证,如验证程序循环次数,数组越界问题,无法访问的指令等等。只有校验通过的字节码才会提交到JIT编译成可直接执行的机器指令。同时,eBPF对提交程序提出限制,如程序大小限制,最大可使用堆栈大小限制,可调用函数限制,循环次数限制等。

从上面的架构图可以看出,eBPF在内核态会依赖内核探针进行工作,其中kprobes实现内核函数动态跟踪;uprobes实现用户函数动态跟踪;tracepoints是内核中的静态跟踪点;perf_events支持定时采样和PMC。

应用

初探eBPF

官网[1]显示,eBPF发展至今在诸多场景下均有实践。例如,eBPF技术中XDP内核钩子适合应用于高性能的网络包处理,可为现代数据中心和云原生环境提供负载均衡。或者,eBPF天然具备的“活体检测”能力可以在内核态进行性能监控与故障诊断。再或者,eBPF建立在查看和理解所有系统调用的基础上,可以为主机安全、网络安全作业提供更丰富的上下文。

开发工具

BCC

BCC[5]是一个基于eBPF的用于创建内核跟踪和操作程序的开源工具包,其使用Python作为前端语言,使用C语言做内核检测语言。

初探eBPF

图中展示了BCC的诸多小工具,如跟踪TCP活动链接的tcpconnect,用于跟踪内核OOM的oomkill等等。

BPFTrace

BPFTrace[6]是基于eBPF的一种高级追踪语言,其使用LLVM作为BPF字节码的编译工具。

初探eBPF

有意思的是,受awk和C语言灵感而开发的BPFTrace语言和经典的systemtap十分相似,都可以提供“一句话”式观测程序。文章[4]将两者进行对比。简单来说BPFTrace更安全,更开箱即用,而systemtap使用了内核module,能力更强更灵活。

bpf2go

bpf2go[7]是一个通用的eBPF go语言库,由Cloudflare和Cilium两家共同维护。

bpf2go提供eBPF编译能力,并支持在go程序中嵌入eBPF程序。

https://github.com/cilium/ebpf/tree/master/examples 仓库提供了很多案例,其中也包含tcp_connect的go实现。

eBPF相关的开发工具非常之多,至此不再一一举例。

实验

接下来我们以一个实验题目来看下如何使用BCC完成内核态函数观测。

题目

假设Linux操作系统用户态中运行着一个进程,它每隔n秒(n在0~5之间)就会向一个随机生成的IP+端口发送一个UDP数据包。我们希望通过观测网络流量的方式不断打印出哪个进程在向哪个IP+端口发送UDP包,从日志分析的角度找到该程序。

注:本实验在Centos7 3.10.0-1160.45.1内核版本下完成

初探eBPF

先把这个发送udp的程序跑起来,然后假装我们不知道它的存在:)

BCC是基于eBPF的开发工具,可以提供hook内核函数的能力,从而打印出需要的信息。然而,使用BCC工具hook内核函数,首先要知道一个程序发送udp数据包会调用哪些syscall与内核函数,从而寻找合适的hook点。

strace工具可以帮忙找到syscall函数,而再往下的内核函数调用栈,需要阅读内核代码,或debug,或查找资料来完成。

通过查阅资料[8],可以找到发送UDP的调用栈大致如下:

初探eBPF

可以看出,linux内核向用户态提供统一的函数入口,而越往下则会按不同协议拆分进行不同函数的调用。这里主要关注udp_sendmsg()udp_send_skb()两个函数。

由于udp协议既可以每次sendto指定目的地址,也支持先connect绑定目的地址再发送。两种方式的差异导致目的IP+端口信息在udp_sendmsg()函数不同位置的参数中。为了程序编写方便,我们选择另一个获取信息相对统一的函数udp_send_skb()进行hook。

初探eBPF

【原理】一节所述,eBPF程序分两部分,一部分是向内核注入的字节码程序,在BCC工具集中需要使用C语言编写。另一部分是获取内核向用户态传递的数据并打印。

在如上程序中,“kprobe__”前缀函数表示创建一个kprobe内核函数hook点,这里hook的是udp_send_skb()程序逻辑很简单,从flowi4结构体中获取IP+端口信息,以及ebpf提供了helper函数可以获取执行当前内核函数的进程信息。最后,通过自定义的perf_event(这里指BPF_PERF_OUTPUT(udp_events))传递出来即可。

我找了一台流量干净的云主机运行该程序,看下效果:

初探eBPF

可见,进程18871这个Python程序在向不固定的IP+端口发送UDP数据。

初探eBPF

找到了,是它!

在学习eBPF的过程中也遇到了很多不懂的问题。例如,上述程序获取saddr就不能写在结构体初始化时,这也是我没能理解的一个问题。另外,若行文有误,欢迎指正 🙂

文末,再添个小疑问吧。

左边跑着udp观测程序,右边用dig @8.8.8.8 www.baidu.com做了个DNS查询。为什么左侧显示的程序不是dig而是isc-worker00呢?

初探eBPF


参考与引用

[1] https://ebpf.io
[2] https://www.tcpdump.org/papers/bpf-usenix93.pdf
[3] https://amslaurea.unibo.it/19622/1/berkeleypacketfilter_distefano.pdf
[4] https://lwn.net/Articles/852112/
[5] https://github.com/iovisor/bcc
[6] https://github.com/iovisor/bpftrace
[7] https://github.com/cilium/ebpf
[8] 用“芯”探核:基于龙芯的Linux内核探索解析
[9] https://blog.crazytaxii.com/posts/what_is_ebpf/

[10] https://zhuanlan.zhihu.com/p/182344856
[11] https://zhuanlan.zhihu.com/p/469860384
[12] https://events19.linuxfoundation.org/wp-content/uploads/2017/12/oss-eu-2018-fun-with-dynamic-trace-events_steven-rostedt.pdf
[13] https://blog.yadutaf.fr/2016/03/30/turn-any-syscall-into-event-introducing-ebpf-kernel-probes/
[14] https://www.ffutop.com/posts/2019-10-12-bpf/






About us

初探eBPF

陌陌安全
致力于以务实的工作保障陌陌旗下所有产品及亿万用户的信息安全
以开放的心态拥抱信息安全机构、团队与个人之间的共赢协作
以自由的氛围和丰富的资源支撑优秀同学的个人发展与职业成长


/   往 期 分 享   /

初探eBPF
App合规实践3000问之二
初探eBPF
陌陌合规审计平台Bombus开源2.0

初探eBPF
「陌陌安全」
扫上方二维码码关注我们,惊喜不断哦

M   O   M   O   S   E   C   U   R   I   T   Y


原文始发于微信公众号(陌陌安全):初探eBPF

版权声明:admin 发表于 2022年5月18日 下午3:01。
转载请注明:初探eBPF | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...