LWN:在kernel內(nèi)處理暴力嘗試攻擊!
關注了就能看到更多這么棒的文章哦~
Handling brute force attacks in the kernel
By Jake Edge
March 17, 2021
DeepL assisted translation
https://lwn.net/Articles/849531/
針對 Linux 系統(tǒng)的若干種攻擊都依賴于對 fork()系統(tǒng)調用進行暴力調用(brute-force),因此,一個名為 "Brute" 的 Linux 安全模塊(LSM) 最近出現(xiàn)了,用來檢測、挫敗此類攻擊。許多種攻擊方式中都會重復進行 fork()調用,例如對 Stack Clash 漏洞或 Heartbleed 風格的漏洞的利用過程。最近 Brute patch set 第 6 版也已經(jīng)公布出來,看起來它離 mainline 越來越近了。
自從 2020 年 9 月 John Wood 首次以 RFC 的形式發(fā)布這個 patch set 以來,它一直在演進中(當時過了幾天 Kees Cook 重發(fā)出來的版本會更容易有個全面印象)。它最初被稱為 "fork brute force attack mitigation "或 "fbfam",但這個名字在 Jann Horn 和 Cook 看來過于晦澀難明了。此外,有人建議把它變成一個 LSM。這兩個建議在 10 月發(fā)布的第 2 版中都被采納了。
但類似的想法其實更早的時候就有了。grsecurity 這組 kernel patch 中早就有 GRKERNSEC_BRUTE 功能,來防護那些對服務端程序使用暴力調用 fork()方式的攻擊,以及對 setuid/setgid 可執(zhí)行文件的利用。2014 年 Richard Weinberger 的一個 patch 也使用了類似的技術,如果 fork 出來的子程序因 fatal error(意味著它可能是正在進行的攻擊中的一部分)而結束,就會對 fork()調用延后處理。這項工作沒有進一步的進展了,所以 Cook 在內(nèi)核自我保護項目(KSPP,kernel self-protection project)的 GitHub 倉庫中添加了一個 issue,這也是 Wood 了解到這個想法來源。
在 documentation patch中,Wood 描述了 Brute LSM 會對哪些行為進行保護。基本來說,有幾種攻擊都是多次調用 fork()來得到攻擊者所期望獲得的 memory layout;每個被 fork 的子進程都可以通過各種方式探測系統(tǒng)信息,如果這些探測失敗并導致子進程崩潰了,就會直接再 fork 另一個子進程來再次嘗試。因為用 fork()創(chuàng)建的子進程與父進程共享相同的 memory layout,所以只要某一次能探測成功,就可以提供一些信息用來克服地址空間布局隨機化(ASLR,address-space layout randomization),確定 stack canaries 的值(也就是棧中重要信息),或者用于其他惡意目的。
Brute 采用了與 grsecurity 或 Weinberger 的 patch 不相同的做法,當檢測到問題時,它不會簡單地推遲后續(xù)的 fork()調用。相反,Brute 會殺死所有與攻擊相關的進程。此外,Brute 還能檢測到其他種類的 fork()攻擊,包括那些探測父進程而非子進程的攻擊。它會只關注那些越過特權邊界的進程中的崩潰,希望減少誤報的數(shù)量。
它是根據(jù)崩潰率(rate of crashes)來決策的,而不是崩潰一次就判定為有問題。Brute 收集了依據(jù) fork 關聯(lián)起來、尚未用 execve()執(zhí)行新程序的這些進程中發(fā)生的 "faults"數(shù)量。所有這些進程之間會共享一個 brute_stats 結構;執(zhí)行一個新程序的話就會導致用一個新的 brute_stats 結構來跟蹤新的 fork() 關系中的 faults(如果有的話)。
從一個進程被啟動,到它或它的任何共享其內(nèi)存布局的子進程(即沒有調用過 execve())發(fā)生了 crash,或在多次 crash 之間的時段,這些時長會最終被用來判斷是否發(fā)生攻擊。但為了不至于太敏感,一旦發(fā)生 5 次 crash,就會計算出這段時間的指數(shù)移動平均線(EMA,exponential moving average)。EMA 會被用于判斷是否發(fā)生了 "fast brute force" 這種類型的攻擊。如果崩潰之間的周期 EMA 下降到 30 秒的閾值以下,就會觸發(fā)對攻擊的防護機制(attach mitigation)。對于 "slow brute force" 類型,會拿 fork 關系相關進程中的 crash 絕對數(shù)量與 200 這個閾值進行比較。可能今后會需要能有什么方式來配置這些值。
檢測 crash 是利用了 task_fatal_signal() 這個 LSM hook,它是這組 patch set 中的第一個 patch 所加入的。每當內(nèi)核向一個進程傳遞了 fatal signal 時,就會調用到這個 hook。Brute 還使用了已經(jīng)存在的 task_alloc() hook 來檢測 fork() 調用,以及 bprm_committing_creds() hook 來檢測 execve()調用,還有 task_free() hook 來進行清理。
安全邊界檢查(security boundary check)是通過檢測在執(zhí)行新程序過程中用戶和組 ID(real 、effective、saved、filesystem 等各種 ID)發(fā)生過哪些變化來實現(xiàn)的。patch 中沒有提到 Linux capabilities,但實際上如果 capability 有改動,也會表明正在跨越特權邊界,也許這是以后會增加的內(nèi)容。除了 ID 變化之外,還用 socket_sock_rcv_skb()LSM hook 來檢測是否使用了網(wǎng)絡。總之是將 crash 檢查只限制在那些執(zhí)行 setuid/setgid 程序跨越特權邊界、或者進行網(wǎng)絡數(shù)據(jù)接收的進程上。這樣做的目的就是為了減少誤報的數(shù)量。
在隨 patch 發(fā)出的 changelog 中可以看到,過去幾個版本(為了方便大家作者還都提供了鏈接)所引發(fā)的需要注意的 review 意見不多。在寫這篇文章的時候,最新一輪還沒有得到任何評論。這似乎是一個對某些用戶很有用的功能,如果在內(nèi)核配置時沒有打開,那么就不會給內(nèi)核的其他部分帶來什么影響。新增安全 hook 會在 fatal signal 發(fā)生的情況下被調用,這就是在這種情況下唯一的改變了。LSM 通常被看作是一個地方用來放置只有部分人想要的代碼、并且其他人不想在他們自己的內(nèi)核中受到影響。Brute 似乎很符合這種模式。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關注,關注 LWN 深度文章以及開源社區(qū)的各種新近言論~
