1. 簡介

本報告詳細介紹了針對 CVE-2025-37947 的技術細節,這是一個在 Linux Kernel ksmbd 模組中發現的關鍵 Out-of-Bounds (OOB) write 漏洞。 ksmbd 模組提供了一個 in-kernel SMB server ,實現了檔案共享能力。 Kernel 模組內的漏洞特別嚴重,因為它們可能導致本機權限提升,或在某些情況下導致遠端程式碼執行 (Remote Code Execution, RCE),繞過標準的作業系統安全緩解措施。本次分析專注於 CVE-2025-37947 的根本原因(root cause)、概念驗證 ( Proof-of-Concept )、堆積塑造技術 ( heap shaping techniques) 和 Exploitation 策略,並汲取了近期研究的見解 [1]。

突破Kernel防線:利用ksmbd CVE-2025-37947的Heap Shaping與提權戰術 | 資訊安全新聞

2. ksmbd 和 Kernel 記憶體管理 背景知識

ksmbd Server Message Block (SMB) 協定的 in-kernel 實作,旨在提供高效能的檔案共享。它直接整合到 Kernel 中,這意味著任何漏洞都可能對系統安全造成深遠的影響。瞭解 Kernel 記憶體管理 對於 Exploiting 此類漏洞至關重要。Linux Kernel 採用了各種記憶體分配器 (memory allocators),包括用於較大、實體連續區塊的分頁分配器 ( page allocator ,即 buddy allocator ) 和用於較小、頻繁使用物件的 slab 分配器 ( slab allocators ,例如 SLUB SLAB SLOB ) [1, 15]。

分頁分配器 將實體記憶體組織成 分頁 ( pages ,通常為 4KB),並以二的冪次方的 區塊 ( blocks ) 進行分配,這些區塊被稱為 orders 。例如,order 0 代表一個單一分頁,order 1 代表兩個連續分頁,依此類推。這種階層式結構分配和合併記憶體區塊。對於大於 KMALLOC_MAX_CACHE_SIZE ( 通常為 8192 位元組 ) 的分配,Kernel 會直接向分頁分配器請求分頁[1]。

3. 弱點分析: CVE-2025-37947

3.1. 根本原因

CVE-2025-37947 是一個 out-of-bounds write 漏洞,位於 ksmbd 模組的 ksmbd_vfs_stream_write 函式中。當 vfs objects 設定選項中啟用了 stream_xattr 模組,並且設定了可寫入的共享(share) 時,就會出現這個漏洞。核心問題在於寫入擴展屬性資料 ( extended attribute data ) 時,大小計算處理不當 [1]。

有漏洞的程式碼片段,特別是在 fs/ksmbd/vfs.c 中,涉及以下邏輯 :

  1. // https://elixir.bootlin.com/linux/v5.15/source/fs/ksmbd/vfs.c#L411
  2. static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
  3.   size_t count)
  4. {
  5.     char *stream_buf = NULL, *wbuf;
  6.     struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);
  7.     size_t size;
  8.     ssize_t v_len;
  9.     int err = 0;
  10.     
  11.     ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n",
  12.         *pos, count);
  13.     size = *pos + count;
  14.     if (size > XATTR_SIZE_MAX) { // [1] Vulnerable check
  15.         size = XATTR_SIZE_MAX;
  16.         count = (*pos + count) - XATTR_SIZE_MAX; // [2] Count adjustment
  17. }
  18.     wbuf = kvmalloc(size, GFP_KERNEL | __GFP_ZERO); // [3] Allocation based on truncated size
  19.     stream_buf = wbuf;
  20.     memcpy(&stream_buf[*pos], buf, count); // [4] Out-of-bounds write occurs here
  21.     // .. snip 
  22.     if (err < 0)
  23.         goto out;
  24.     fp->filp->f_pos = *pos;
  25.     err = 0;
  26. out:
  27.     kvfree(stream_buf);
  28.     return err;
  29. }

漏洞的發生是因為 XATTR_SIZE_MAX 通常是 65536 位元組 (16 分頁)。如果 *pos count 的總和大於 XATTR_SIZE_MAX ,則 size 變數會在 [1] 處被截斷(truncated) 為 XATTR_SIZE_MAX 。然而, count 變數會在 [2] 處被調整,以反映原始總和與 XATTR_SIZE_MAX 之間的差異。這意味著如果攻擊者 將 *pos 設定為 XATTR_SIZE_MAX 並提供一個小的 count (例如 8 位元組),則 [3] 處的 kvmalloc 呼叫將分配大小為 XATTR_SIZE_MAX 的緩衝區( buffer )。隨後, [4] 處的 memcpy 操作將嘗試從 stream_buf[*pos] 開始寫入 count 位元組,從而寫入超出已分配緩衝區的邊界[1]。

舉例來說,設定 *pos = 0x10000 count = 0x8 將導致 memcpy(&stream_buf[0x10000], buf, 8) ,從而導致 8 位元組的 out-of-bounds write。攻擊者還可以通過操縱 *pos 來控制偏移量(offset),從而實現對相鄰記憶體的精確破壞[1]。

3.2. 漏洞觸發的設定

為了觸發這個漏洞, ksmbd 設定必須包含一個啟用了 streams_xattr 模組的可寫入共享:

[share]
        path = /share
        vfs objects = streams_xattr
        writeable = yes

3.3. 漏洞流程圖

下圖說明了導致 out-of-bounds write 漏洞的控制流程 :

graph TD A[Attacker sends crafted SMB request] --> B{ksmbd_vfs_stream_write}; B --> C{Calculate 'size'}; C --> D{Is size > XATTR_SIZE_MAX?}; D -- Yes --> E{Truncate size to XATTR_SIZE_MAX}; E --> F{Adjust 'count'}; F --> G{Allocate 'wbuf' with 'size'}; G --> H{memcpy to stream_buf}; H --> I[Out-of-bounds write]; D -- No --> G;

4. 概念驗證 (PoC) 與記憶體佈局

一個最小的 概念驗證 ( Proof of Concept, PoC ) 可以在不一定提升權限的情況下證明此漏洞的可觸及性(reachability)。此類 PoC 通常會認證(authenticate) 到 ksmbd 共享並發送帶有使用者控制屬性的精心製作的 vfs stream 資料 。通過設定 file_offset 0x0000010018ULL length_wr 8 , 攻擊者可以 out-of-bounds 寫入 32 位元組的任意資料(例如 0xaa 0xbb 模式)。像 GDB 這樣的除錯器可以通過檢查已分配位址處的記憶體來確認此 OOB write [1]。

(gdb) c
Continuing.
ksmbd_vfs_stream_write+310 allocated: ffff8881056b0000

Thread 2 hit Breakpoint 2, 0xffffffffc06f4b39 in memcpy (size=32, 
    q=0xffff8881031b68fc, p=0xffff8881056c0018)
    at /build/linux-eMJpOS/linux-5.15.0/include/linux/fortify-string.h:191
warning: 191	/build/linux-eMJpOS/linux-5.15.0/include/linux/fortify-string.h: No such file or directory
(gdb) x/2xg $rsi
0xffff8881031b68fc:	0xaaaaaaaaaaaaaaaa	0xbbbbbbbbbbbbbbbb

GDB輸出 清楚地顯示 memcpy 操作正在從來源 q 向目標 p 寫入 32 位元組 ( size=32 ),其中 p 0xffff8881056c0018 。鑑於已分配緩衝區從 0xffff8881056b0000 開始,並且 XATTR_SIZE_MAX 0x10000 (65536 位元組 ),在 0xffff8881056c0018 處的寫入確實是 out-of-bounds 的,具體來說是超出已分配 0x10000 邊界 0x18 位元組[1]。

5. 用於 Exploitation 的 Heap Shaping

Exploiting Kernel OOB writes 通常需要對 Kernel 堆積佈局進行精確控制,這項技術被稱為 heap shaping 。目的是將目標物件(target object) 放置於緊接在有漏洞的緩衝區之後,以便 OOB write 以受控方式破壞目標物件。在 CVE-2025-37947 的環境中, kvzalloc 函式被用於分配,它是 kvmalloc 的封裝(wrapper)。 kvmalloc 嘗試使用 kmalloc 分配實體連續的記憶體,如果有必要則會退回到 vmalloc [1]。

由於分配大小(16 分頁或 0x10000 ) 大於 KMALLOC_MAX_CACHE_SIZE (8192 位元組),Linux Kernel的分頁分配器 ( buddy allocator ) 會直接介入。這意味著 Exploitation 策略必須集中於操縱分頁分配器。挑戰在於在有漏洞的 kvzalloc 呼叫之前,在記憶體中建立一個 16 分頁的連續空閒空間(free space),確保 stream_buf 被放置在這個受控區域[1]。

為了實現這一點,攻擊者可以分析 Kernel 的 slab caches 和分頁分配器統計資料。 /sys/kernel/slab/*/order 檔案揭示了用於分配 slabs 的分頁順序。例如,許多常見的 Kernel 物件使用 order-3 分頁。通過檢查 /proc/pagetypeinfo ,可以每個 order 和遷移類型(migrate type) 的空閒分頁數量(例如 Unmovable Movable )。該策略涉及耗盡特定 order-3 和 order-4 空閒列表項目(freelist entry),迫使分配器拆分更高 order 的區塊(例如 order-5) 來滿足請求。這可以建立一個場景,其中目標物件(例如 msg_msg 物件) 被放置在 stream_buf 之後,使其易受 OOB write 的破壞[1]。

例如,分配大量大小為 4096 位元組的 msg_msg 物件(以符合 kmalloc-cg-4k ) 可以幫助塑造堆積。通過接收訊息來建立空洞(holes), stream_buf 剛好落在目標 msg_msg 物件之前的機率會顯著增加,從而允許通過 out-of-bounds write 破壞其記憶體[1]。

6. Exploitation 策略

一旦 out-of-bounds write 被可靠地觸發且目標物件被破壞,下一步就是實現本機權限提升(local privilege escalation)。 原始文章提到嘗試破壞分段(segmented) msg_msg 物件中的 next 指標(pointer),但轉向了類似 CVE-2021-22555 中描述的策略:將 \x00\x00 轉換為 10000$。這種方法特別有效,因為 OOB write 目標是實體分頁(physical pages) 而非 slab 物件,簡化了跨快取(cross-cache)攻擊的考慮[1, 13]。

Exploitation 流程通常涉及多個階段 :

  1. Heap Spraying: Kernel 中分配大量 msg_msg 物件,為控制放置堆積做準備。
  2. Triggering OOB Write: 觸發 CVE-2025-37947 漏洞以分配 stream_buf 並覆寫主要訊息(primary message) 的 next 指標。這種操縱會導致兩個主要訊息指向同一個次要訊息(secondary message),建立碰撞(collision)。
  3. Detecting Corruption: 通過用其佇列(queue)索引標記每個訊息,並使用 msgrcv(MSG_COPY) 掃描佇列以尋找不匹配的標記,來識別被破壞的配對(pair)。
  4. Arbitrary Read/Write Primitive: 通過小心地釋放真實的次要訊息,然後釋放假的次要訊息,攻擊者可以獲得任意讀/寫原語(primitive)。該原語對於進一步的 Exploitation 步驟至關重要,例如洩露 Kernel 位址(address) (以繞過 KASLR ) 和覆寫關鍵 Kernel 資料結構(data structures)。
  5. Privilege Escalation: 擁有任意讀/寫能力後,攻擊者可以修改當前程序的敏感 Kernel 結構,例如 credentials ,以獲取 root 權限。這通常涉及用精心製作的 cred 結構 覆寫當前任務(task) 的 cred 結構,該結構授予完全能力(capabilities)。

文章強調,通過 BPF 腳本 (scripts) 確認分配位址對於確保 Exploit 的正確(alignment) 和可預測性至關重要。例如,分析來自 bpf-tracer.sh 等工具的輸出可以顯示已分配分頁的分佈,並確認 heap shaping 是有效的 [1]。

$ sudo ./bpf-tracer.sh
...
$ grep 4048 out-4096.txt  | egrep ".... total" -o | sort | uniq -c
    511 0000 total
    510 1000 total
    511 2000 total
    512 3000 total
    511 4000 total
    511 5000 total
    511 6000 total
    511 7000 total
    513 8000 total
    513 9000 total
    513 a000 total
    513 b000 total
    513 c000 total
    513 d000 total
    513 e000 total
    513 f000 total

此輸出展示了受控的分配分佈,這對於成功的 heap shaping 和隨後的 Exploitation 至關重要。通過覆寫特定位元組(例如 \x05\x00 )建立碰撞的能力,進一步完善了 Exploit 的精準度,實現了堆疊樞軸(stack pivoting) 和其他進階技術[1]。

7. 結論

Linux Kernel的 ksmbd 模組中的 CVE-2025-37947 由於其本機權限提升的潛力而代表了一個重大的安全漏洞。 ksmbd_vfs_stream_write 中的 out-of-bounds write ,結合複雜的 heap shaping 技術,允許攻擊者獲得對 Kernel 記憶體的控制。本研究報告闡明了該漏洞的技術細節、觸發所需的設定、涉及 heap shaping 的記憶體管理概念以及多階段的 Exploitation 策略。瞭解此類漏洞對於開發穩健的防禦並確保 Kernel 級別組件的完整性至關重要。