當AI讓0-day漏洞感覺像N-day漏洞
本文深入分析了作者如何藉助AI發現並利用Linux內核net/sched子系統中的一個釋放後使用(UAF)漏洞,實現本地權限提升(LPE)。詳細介紹了競爭條件的發現、優化過程,以及各種利用技術,並展示了利用AI加速漏洞開發各個環節的經驗。
當AI讓0-day漏洞感覺像N-day漏洞
引言
在對net/tls漏洞進行n-day分析併為已修補的net/rxrpc漏洞編寫exp之後,作者轉向了0-day漏洞挖掘。在AI的幫助下,他在net/sched中發現了一個釋放後使用(UAF)漏洞,並據此創建了一個本地權限提升(LPE)exploit。本文深入介紹了該exploit的技術細節,以及如何針對TyphoonPwn 2026中的CentOS 9桌面進行優化。此外,還簡要展示了在kernel/events/core.c中發現的另外兩個可利用漏洞(其中一個已有LPE exploit)。
AI的使用
與之前為net/rxrpc的n-day編寫exp相比,作者更注重快速完成和改進這個exploit,而不是從頭全面理解每個方面。因此,他使用AI來加速各個階段:發現漏洞、生成KASAN PoC以及改進競爭條件。AI在快速迭代方面確實很有幫助,但推理能力仍然不足,且有明顯的盲點。在微調時,作者仍然需要運用自己的判斷力。
net/sched的簡要概念
net/sched是Linux中的包調度子系統,位於設備驅動之上,決定何時、以何種順序以及是否傳輸數據包。它還通過netlink提供API來配置包處理規則。每個網絡設備都附加一個Qdisc(隊列規則),其中包含所有配置數據。為了決定如何處理給定數據包,net/sched引入了鏈、過濾器和動作。鏈是過濾器的有序列表,過濾器檢查數據包中的特定屬性,然後根據結果決定執行什麼動作。net/sched的設計允許最大程度地重用組件——多個網絡設備可以共享同一個Qdisc。關鍵的是,動作可以在同一網絡命名空間內共享,並通過“索引”唯一標識。一個per-net的radix樹action_idr記錄所有動作對象,並支持通過索引查找,這由tcf_idr_check_alloc函數實現。
漏洞
該漏洞是一個鎖不匹配問題:tcf_idr_check_alloc()僅持有rcu_read_lock()就訪問動作idr,而動作釋放時持有idrinfo->lock和rtnl_lock(),但沒有等待RCU寬限期(即直接kfree)。這導致了一個競爭條件:動作可以在查找過程中被釋放,從而產生UAF場景。成功利用UAF需要在同一窗口內既釋放又回收動作(覆蓋tcfa_refcnt)。競爭的基本結構是:CPU0查找動作,CPU1刪除動作,CPU2回收並設置tcfa_refcnt為非零。
作者最初使用RTM_NEWACTION和RTM_DELACTION證明了漏洞,但這些操作需要init命名空間中的CAP_NET_ADMIN,因此不可行。於是轉而使用RTM_NEWTFILTER和RTM_DELTFILTER。通過使用clsact qdisc和flower過濾器(設置了DOIT_UNLOCKED標誌),可以避免持有rtnl_lock。此外,利用還需要非特權用户命名空間啓用。
競爭優化
第一個優化是使用timerfd和epoll的窗口擴大技術。通過設置timerfd,在特定時間後觸發硬件中斷,處理程序會喚醒所有等待者。附加大量epoll對象可以延長等待者列表,從而阻塞CPU。第二個優化是讓不同線程在不同的鏈上創建過濾器,每個鏈有自己的互斥鎖,使用獨立鏈可以顯著加速競爭。第三個優化是主要重構:利用錯誤路徑消除大量開銷。設置兩種競爭線程:binder(綁定器)和deleter(刪除器)。
Binder線程利用過濾器創建的錯誤路徑:提交一個包含兩個動作的過濾器創建請求——動作42和一個無效格式動作。動作42被成功獲取(競爭發生於此),但讀取第二個動作失敗導致中止,過濾器從未創建,動作42也未被插入idr。這節省了刪除新創建過濾器的開銷。Deleter線程創建一個包含動作42的過濾器然後刪除它,其作用是將動作42插入idr。最終設置:N個binder線程和一個deleter線程在不同CPU上運行,全部操作動作42。利用時間從超過15分鐘縮短到約5秒。
kASLR泄露
利用開始時,作者使用EntryBleed實現泄露kASLR基址。
利用原語
tc_action對象豐富,在回收後的代碼路徑中存在許多有用原語,例如任意kfree user_cookie->data和user_cookie。本exploit使用了ops虛表中的間接調用。tc_action從kmalloc-256高速緩存分配,作者用user_key_payload對象回收。為了避免崩潰,將數據的前8個字節設置為指向NULL的指針(通過kASLR泄露獲得)。更優的方法是將數據長度設為192字節,使臨時緩衝區落入不同的kmem_cache。
RCU
在獲得RIP控制之前,需要簡要了解Linux RCU機制。RCU是一種低成本同步機制,所有讀取在“寬限期”內完成,寫入在之後。通過call_rcu(head, func)函數延遲寫入,它接受rcu_head指針和函數指針,將回調添加到每CPU鏈表中,在寬限期後調用。RCU的rcu_head結構包含next指針和func函數指針。利用時,通過控制user_key_payload中的rcu_head結構,可以劫持控制流。