摘要
本報告詳細技術分析了在 Microsoft Windows Cloud Files MiniFilter (
cldflt.sys
) 中發現的
Time-of-Check to Time-of-Use (TOCTOU) Race Condition
弱點。此缺陷已於 October 2025 修補,並被指派為 CVE-2025-55680,它允許攻擊者藉由在任意、特權位置建立檔案或目錄來實現權限提升 (Privilege Escalation)。此弱點發生在
HsmpOpCreatePlaceholders()
函式處理
CfCreatePlaceholders()
請求的過程中。我們檢視了
Race Condition
的機制、Cloud Files MiniFilter 驅動程序的角色、涉及多執行緒 (multithreading) 和連接點 (junction points) 的漏洞攻擊方法,以及隨後的透過 DLL 側載 (DLL side-loading) 進行權限提升的過程。本報告強調了此弱點及其漏洞攻擊的技術複雜性。
1. 簡介
權限提升弱點是資安缺陷中的關鍵類別,它允許攻擊者在系統中取得更高的存取權限。本報告調查了一個重大的
Time-of-Check to Time-of-Use (TOCTOU) Race Condition
弱點,CVE-2025-55680,它存在於 Microsoft Windows Cloud Files MiniFilter (
cldflt.sys
) 中。這個弱點在 March 2024 被發現,並在 October 2025 獲得修補,它允許攻擊者繞過檔案名稱驗證檢查,並在受保護的系統位置建立任意檔案或目錄,最終導致權限提升 [1]。本分析深入探討了此弱點的技術細節、底層的 Windows Cloud Files 架構、漏洞攻擊步驟,以及用來實現更高權限的方法。
2. Microsoft Windows Cloud Files MiniFilter 概觀
Microsoft Cloud API 促進了檔案和目錄在本地主機與遠端雲端服務(例如 OneDrive)之間的同步。此功能依賴於
cldapi.dll
函式庫,而該函式庫由 Cloud Files MiniFilter 驅動程序 (
cldflt.sys
) 所支援。
cldflt.sys
驅動程序是一個檔案系統篩選 (filter) 驅動程序,它向篩選管理器 (Filter Manager) 註冊,並透過各種 I/O 控制 (IOCTL) 碼和主要函式類型向雲端應用程序公開檔案系統功能 [1]。
2.1. Cloud Files 概念
Cloud Files 生態系統中的關鍵概念包括:
- 同步根目錄 (Sync Root Directory): 一個已註冊的資料夾,其中的檔案和目錄會進行同步。
- Placeholder Files: 檔案雖然在本地存在,但其內容儲存在雲端。當被存取時,它們會被補充水分 (hydrated)(下載內容)。
- 補充水分政策 (Hydration Policy): 定義了檔案內容何時從雲端下載。
- 填充政策 (Population Policy): 定義了目錄如何從雲端內容填充。
同步提供者 (sync providers) 使用
CfRegisterSyncRoot()
API 將目錄註冊為同步根,指定管理同步行為的各種政策 [1]。
2.2. Cloud Files MiniFilter 驅動程序互動
cldflt.sys
驅動程序透過為主要函式碼(例如
IRP_MJ_CREATE
、
IRP_MJ_READ
和
IRP_MJ_FILE_SYSTEM_CONTROL
)註冊的 Callback Function 來攔截各種 I/O 請求程序包 (IRPs)。對於
NtDeviceIoControlFile()
和
NtFsControlFile()
使用者空間 (user-space) APIs,驅動程序定義了
HsmFltPreFILE_SYSTEM_CONTROL()
和
HsmFltPostFILE_SYSTEM_CONTROL()
Callback Function,它們分別在實際操作之前和之後執行 [1]。
此弱點特別針對一個客製化的 IOCTL,
0x903BC
,它被
cldapi.dll
用於像
CfCreatePlaceholders()
這樣的操作。當發出帶有
0x903BC
控制碼、Tag
0x9000001A
和
OpType
0xC0000001
的 IOCTL 時,表示它是一個
CfCreatePlaceholders
請求 [1]。
CfCreatePlaceholders()
API 接受一個
BaseDirectoryPath
和一個
CF_PLACEHOLDER_CREATE_INFO
結構的陣列。
CF_PLACEHOLDER_CREATE_INFO
結構包含一個
RelativeFileName
(
LPCWSTR
)、檔案 metadata 和身分識別資訊 [1]。
0x903BC
IOCTL 的輸入緩衝區遵循
ioctl_0x903BC
資料結構,其中包含一個
placeholder_payload
,它指向一個
create_placeholder_t
結構的陣列。
create_placeholder_t
結構儲存了相對檔案名稱 (
relName
) 和檔案身分識別 (
fileid
) 的位移 (offsets) 和長度 (lengths),以及檔案屬性 (attributes) [1]。
3. 弱點分析 (CVE-2025-55680)
TOCTOU
弱點位於
cldflt.sys
中實作的
HsmpOpCreatePlaceholders()
函式中,用於處理
CfCreatePlaceholders()
請求。關鍵缺陷在於檔案名稱驗證與實際檔案建立之間存在一個
Race Condition
[1]。
3.1. HsmpOpCreatePlaceholders() 函式流程
HsmpOpCreatePlaceholders()
函式透過以下步驟處理請求:
-
使用
IoAllocateMdl()為使用者空間緩衝區 (placeholderPayload) 分配一個 MDL (Memory Descriptor List)。 -
使用
MmMapLockedPagesSpecifyCache()將使用者空間緩衝區對映 (Mapping) 到 Kernel 空間。這會建立一個共享實體頁面 (shared physical page) 來支援使用者空間和 Kernel 對映的緩衝區,這表示在使用者空間中的修改會反映在 Kernel 對映的區域 [1]。 -
解析
placeholderPayload緩衝區並將其資料複製到堆疊變數 (stack variable)placeholderPayload_stack中。 -
驗證包含在
relName欄位中的檔案名稱。此驗證會檢查是否存在\或:字元。此檢查是作為 CVE-2020-17136 的更新程式引入的 [1]。 -
如果檔案名稱被視為有效,則使用目錄 Handle 和檔案名稱(指向 Kernel 對映的使用者空間緩衝區)準備
ObjectAttributes。 -
呼叫
FltCreateFileEx2()來建立檔案或目錄 [1]。
3.2. Race Condition
此弱點源於檔案名稱驗證(步驟 4)與透過
FltCreateFileEx2()
建立實際檔案(步驟 6)之間的時間窗口。由於使用者空間緩衝區被對映到 Kernel 空間,並且在驗證後未受到修改保護,攻擊者可以在此窗口期間更改對映記憶體中的
relName
字串。具體來說,攻擊者可以在檔案名稱通過驗證後、但在
FltCreateFileEx2()
被呼叫之前,將一個
\
字元 插入到檔案名稱中 [1]。
FltCreateFileEx2()
函式在呼叫時如果沒有特定的旗標來處理符號連結 (symlinks)/junctions,它將會跟隨 junction point。這允許攻擊者最初將
relName
設定為類似
JUSTASTRINGDnewfile.dll
的內容。如果攻擊者贏得
Race Condition
,他們可以將其更改為
JUSTASTRING\newfile.dll
。如果
JUSTASTRING
是一個指向不可寫入系統目錄(例如
C:\Windows\System32
)的 junction,那麼
FltCreateFileEx2()
將會在該特權位置建立
newfile.dll
[1]。
下圖說明了 TOCTOU Race Condition :
圖 1:HsmpOpCreatePlaceholders() 中的 TOCTOU Race Condition
3.3. 程式碼片段分析
HsmpOpCreatePlaceholders()
內部的相關程式碼區段,如文章中所述,Highlight了驗證和檔案建立步驟:
- __int64 __fastcall HsmpOpCreatePlaceholders(
- PFLT_INSTANCE *a1,
- __int128 *DirHandle,
- int syncPolicy,
- create_placeholder_t *placeholderPayload,
- ULONG placeholderPayload_size,
- int *out)
- {
- // ... (initializations and other code)
- // [4] Allocation and mapping of user-space buffer into kernel space
- MemoryDescriptorList = IoAllocateMdl(placeholderPayload, placeholderPayload_size, 0, 0, 0i64);
- // ... (error handling)
- MmProbeAndLockPages(MemoryDescriptorList, 1, IoReadAccess);
- // ... (mapping to MappedSystemVa)
- mmapped_userspace_region = MappedSystemVa;
- while ( 1 )
- {
- // [7] Copying payload info to stack variable
- memset(&placeholderPayload_stack, 0, sizeof(placeholderPayload_stack));
- v16 = (create_placeholder_t *)((char *)mmapped_userspace_region + v53);
- // ... (copying specific fields)
- // [8] Filename validation loop
- v21 = (int)v51;
- v22 = 0;
- if ( HIWORD(relName_sz) >> 1 )
- {
- while ( 1 )
- {
- v23 = *(_WORD *)((char *)v51 + 2 * v22 + relName_offset);
- if ( v23 == '\\' || v23 == ':' ) // Check for '\' or ':'
- break; // Validation fails if forbidden characters are found
- if ( ++v22 >= (unsigned __int16)(HIWORD(relName_sz) >> 1) )
- goto LABEL_51;
- }
- // ... (error handling and return)
- }
- // [9] Preparing ObjectAttributes with ObjectName pointing to mmapped_userspace_region.relName
- *((_QWORD *)&v65 + 1) = (char *)v51 + placeholderPayload_stack.relativeName_offset;
- LOWORD(v65) = placeholderPayload_stack.relativeName_len;
- WORD1(v65) = placeholderPayload_stack.relativeName_len;
- ObjectAttributes.Length = 48;
- ObjectAttributes.RootDirectory = dirHandle_cp;
- ObjectAttributes.Attributes = 576;
- ObjectAttributes.ObjectName = (PUNICODE_STRING)&v65 // Pointer to the mapped user-space buffer
- // ... (other ObjectAttributes fields)
- // [10] File creation call
- LODWORD(v24) = FltCreateFileEx2(
- Filter,
- Instance,
- &FileHandle,
- &FileObject,
- 0x100180u,
- &ObjectAttributes,
- &IoStatusBlock,
- &AllocationSize,
- FileAttributes,
- 0,
- 2u,
- CreateOptions,
- 0i64,
- 0,
- 0x800u,
- &DriverContext);
- // ... (loop continuation or exit)
- }
- }
關鍵的觀察結果是,指定
FltCreateFileEx2()
檔案 Path 的
ObjectAttributes.ObjectName
直接指向
mmapped_userspace_region.relName
。這意味著在驗證迴圈 (
[8]
) 完成之後和
FltCreateFileEx2()
(
[10]
) 被呼叫之前,使用者模式應用程序對原始
relName
緩衝區所做的任何更改都會反映在 Kernel 中,從而繞過檢查 [1]。
4. 漏洞攻擊方法
利用這個 TOCTOU Race Condition 需要一個精心策劃的攻擊,涉及多個執行緒 (threads) 和 Windows junction point 的策略性使用 [1]。
4.1. 漏洞攻擊步驟
漏洞攻擊過程可以分解為三個主要步驟:
-
設定環境:
使用
CfRegisterSyncRoot()註冊一個同步根目錄。在此同步根中,建立一個目錄(例如JUSTASTRING)並將其設定為指向不可寫入系統目錄(例如C:\Windows\System32)的 junction point [1]。 -
觸發弱點 (Race Condition):
此步驟涉及多個執行緒並行 (concurrently) 運行以利用
TOCTOU
窗口 [1]:
-
監控執行緒 (Monitor Thread):
持續檢查目標
malicious payload
檔案(例如
C:\Windows\System32\newfile.dll)是否已建立。一旦偵測到,它就會停止 Race Condition 並進入下一個階段。 -
建立
Placeholder
執行緒 (Create Placeholder Threads):
這些執行緒持續呼叫
CfCreatePlaceholders(),目標是同步根目錄。輸入緩衝區中的relName最初設定為一個良性 (benign) 字串,例如JUSTASTRINGDnewfile.dll,並且fileAttributes設定為FILE_ATTRIBUTE_NORMAL。 -
檔案名稱更改執行緒 (Filename Changer Threads):
這些執行緒重複修改使用者空間的
relName緩衝區。具體來說,它們會將一個 字元 (例如JUSTASTRINGDnewfile.dll中的 'D')在其原始值和反斜線 (backslash) (\) 之間切換,並帶有微小的延遲 (delay)。這旨在擊中驗證已通過,但FltCreateFileEx2()呼叫尚未發生的 Race Condition 窗口。
如果檔案名稱更改執行緒在驗證之後成功插入一個
\,relName就會變成JUSTASTRING\newfile.dll。由於JUSTASTRING是指向C:\Windows\System32的 junction ,FltCreateFileEx2()將會跟隨此 junction 並在C:\Windows\System32內建立newfile.dll[1]。 -
監控執行緒 (Monitor Thread):
持續檢查目標
malicious payload
檔案(例如
-
權限提升:
一旦
malicious payload
DLL(例如
newfile.dll)在特權系統目錄中建立,攻擊者就可以利用 DLL 側載 (DLL side-loading) 技術。這涉及放置一個特殊製作的 DLL,該 DLL 將被一個以更高權限運行的合法系統程序所載入,從而以系統級權限執行任意程式碼。檔案建立後,監控執行緒就可以將 malicious payload 內容寫入其中。
5. 結論
Microsoft Windows Cloud Files MiniFilter
TOCTOU
權限提升 (CVE-2025-55680) 突顯了確保複雜作業系統元件安全方面持續存在的挑戰,特別是那些涉及使用者
Kernel
互動和檔案系統操作的元件。
HsmpOpCreatePlaceholders()
內部的
Race Condition
證明了一個看似穩健 (robust) 的檔案名稱驗證如何因其實作中的時間性弱點而被繞過。漏洞攻擊方法結合了多執行緒攻擊、
junction point
和 DLL 側載,突顯了攻擊者用來實現權限提升的複雜技術。這個弱點對開發人員來說是一個重要的提醒,要仔細考慮安全敏感程式碼路徑中的
Time-of-Check to Time-of-Use
情境,同時也提醒系統管理員要迅速安裝更新程式以緩解此類風險。