今天為大家介紹清華大學徐恪老師團隊提出的一個面向無狀態協議攻擊的防御系統——ICMP Filter,其能夠以防御組件的形式熱加載進Linux內核中,監測入站ICMP報文的頻率和語義特性。系統在維持輕量化設計的同時,對潛在的惡意攻擊報文進行提前過濾,并向用戶及時反饋防御日志。目前的實現可以應用于Linux 6.4以上的版本中。
GitHub項目地址:
https://github.com/Internet-Architecture-and-Security/eBPF-based-Defense-Against-TCP-IP-Exploits-via-Forged-ICMP-Errors
01?研究背景:無狀態協議的語義缺失問題
TCP/IP協議棧通過分層設計實現了網絡互聯的標準化與高效性,它定義了數據如何在網絡中封裝、尋址和傳輸,支撐了全球互聯網Internet的互聯互通。其中,無狀態的UDP/ICMP等協議,憑借低開銷、實時性強的特性,廣泛應用于視頻流傳輸、在線游戲、網絡診斷(如ping/traceroute)等場景,靈活滿足了不同應用對可靠性、速度及功能的需求,共同構建了現代網絡通信的基石。
然而,由于UDP/ICMP的無狀態設計特性,在當前廣泛應用的Linux內核實現中并不會專門維護其對應的協議狀態機,而對于這兩種報文合法性的校驗往往采用弱校驗的方式,在弱校驗下攻擊者可以較低的成本輕易構造內嵌報文以欺騙內核協議棧,無狀態協議的語義缺失無疑為攻擊者帶來了可乘之機。近年來,該問題也引起了學術界的關注,在國際四大安全會議上多個研究均利用此機制實現了對TCP連接的攻擊甚至劫持。
本系統通過抓住這類問題的本質,從根源上對協議棧進行防護,并基于Linux內核的eBPF子系統進行實現,相比于Linux內核補丁或內核模塊,具有更好的可移植性和魯棒性。
02?基礎技術:Linux內核利器eBPF介紹
eBPF是一種可以在特權級上下文(如操作系統內核)中運行用戶自定義程序的技術,是對Linux內核中的數據包過濾技術BPF(Berkeley Packet Filter)的擴展,其能夠在不改變內核源碼或加載內核模塊的前提下幫助用戶擴展額外功能,如今已被實現在Linux主線中。
eBPF的核心實現是一個虛擬機,能夠運行自定義的64位的RISC指令集。用戶通過編寫自定義的eBPF程序,通過編譯器生成BPF字節碼,隨后加載進內核中的eBPF子系統執行JIT(Just-in-Time)編譯和驗證,并調用helper API與操作系統運行時進行交互。eBPF子系統中同時實現了eBPF Map,用戶可以通過eBPF程序和系統調用兩種方式訪問eBPF Map,使用API對數據進行讀寫,以實現狀態存儲與通信需求。eBPF通過指定程序類型以將eBPF程序掛載至內核中預設的不同的鉤子處,截至目前eBPF中負責協議棧入站數據包處理的程序類型主要有3類,xdp (Linux 4.8引入), tc (Linux 4.1引入)和netfilter (Linux 6.4引入)。
圖1 Linux中的eBPF實現
03?系統設計:無狀態協議攻擊防御系統
團隊提出的面向無狀態協議攻擊的防御系統主要分為兩個部分,其一是內嵌無狀態協議的ICMP Error報文過濾模塊,其二是ICMP輸入速率限制模塊。防御機制以eBPF的netfilter類程序的方式實現,掛載在NF_INET_LOCAL_IN鉤子處,該鉤子位于Linux內核的IP數據包入站路徑上,對于所有的入站數據包的處理,均會調用該eBPF程序進行額外的過濾和防御。
1.內嵌無狀態協議的ICMP Error報文過濾模塊
當入站數據包為ICMP Error報文時,此模塊會被激活并嘗試過濾具有威脅的數據包。RFC 792中規定,當觸發ICMP Error報文時,需在ICMP的數據字段內嵌觸發該Error報文的原IP報文的前28個字節。28個字節中包含了原報文狀態相關的重要信息,如IP首部的協議字段,TCP/UDP的源目的端口號,TCP的序列號等。對于內嵌的原報文為有狀態報文(TCP),在內核中已存在較強的校驗機制,故不做處理;對于內嵌的原報文為無狀態報文(UDP/ICMP),由于內核并未維護具體狀態信息,故轉而采取了弱校驗,攻擊者可以輕易地構造偽造報文以繞過。如果內嵌報文是被動產生的報文,如ICMP Error/ICMP Echo Reply,由于這類報文并不是由終端主動產生,理論上不應再次觸發ICMP Error報文,故報文過濾模塊對這類報文進行了過濾。特別地,對于ICMP Redirect報文,其主要用于通告終端到目的IP的新的網關選擇,正常情況下只是為了通告較短的路徑,就算按照原來的路徑數據包也能順利送達目的地,但是一旦被攻擊者利用,就可以輕易達成對指定目的IP流量的DoS或者劫持攻擊,故對于這類報文,一旦其中內嵌的原報文為無狀態協議,那么報文過濾模塊也會將其過濾。
圖2 ICMP Filter在Linux內核中的執行流程圖
2.ICMP輸入速率限制模塊
攻擊者在嘗試利用ICMP Error報文進行攻擊時,暴力枚舉可能的內部無狀態報文是一種常見的方式,此外,當偽造的ICMP Error報文通過協議棧的校驗后,攻擊者仍會通過ICMP報文的反饋機制嘗試觀測側信道。以上兩種情況均會產生大量的ICMP報文,在目前版本的Linux內核實現中,只對ICMP報文的輸出速率進行了限制,以防御DoS攻擊,但是并未對輸入速率進行額外限制。考慮到攻擊者有可能會擁有一個IPv4網段,在本模塊中,對來自每個/24網段的ICMP報文進行獨立限速,為防止限速閾值限制產生側信道,每秒鐘隨機接收500~1000個ICMP報文,具體實現通過對每個網段基于eBPF Map獨立維護一個LRU credit表項完成。由于內核線程在處理數據包是并行的,為防止讀寫競爭,對于表項的修改應設計對應的同步互斥機制,一個比較簡單的方式是使用自旋鎖。然而,當攻擊者構造大量ICMP報文時,使用自旋鎖會帶來頭阻問題,在一定程度上甚至會達到DoS攻擊的效果。對此,在此模塊中,使用GCC提供的原子操作指令,通過“嘗試-回退”的方式更新credit值,在避免讀寫競爭的同時近似逼近原本預期達到的效果。
3.防御日志監測模塊
為了方便用戶觀測兩個模塊的防御記錄,以及時做出應對,本系統中通過Ring Buffer類型的eBPF Map實現了日志系統,能夠將內核中eBPF程序實際進行的防御操作及時反饋到用戶空間,在日志信息中包含兩個子模塊具體進行的操作以及被過濾報文的源IP地址。
圖3 ICMP Filter總體架構圖
04?結語
ICMP Filter從無狀態協議攻擊的成因出發,利用Linux的eBPF子系統完整實現了對這類攻擊依賴的主要報文的過濾和防御,并且設置了日志系統將防御記錄第一時間反饋給用戶。團隊后續會繼續對Linux內核協議棧漏洞的系統防御進行深入研究,并與業界和社區開展密切合作,將成果服務于社區生態。
敬請關注團隊后續的更多研究成果發布!