漏洞分析:對CVE-2018-8587(Microsoft Outlook)漏洞的深入分析
寫在前面的話
MicrosoftOutlook是微軟Office套件中的一個元件,它可以用來發送和接收電子郵件,管理聯絡人,記錄和跟蹤日程計劃,或執行其他任務。近期,研究人員在Outlook 2010至Outlook 2019版本以及Office 365 ProPlus中發現了一個堆崩潰漏洞,Windows平臺下的32/64版本均會受到該漏洞影響。攻擊者可使用惡意RWZ檔案來觸發該漏洞,當Outlook收到惡意RWZ檔案內容時,它只會分配少量堆記憶體,並且缺少恰當的邊界檢測,最終導致堆記憶體越界寫入。
復現漏洞
為了復現該漏洞,我們需要執行Microsoft Outlook,然後點選“規則=>管理規則&警報=>選項=>匯入規則”,選擇可以觸發Outlook崩潰的PoC檔案。
下面給出的就是發生崩潰時的棧呼叫情況:
分析漏洞
我們可以從棧呼叫資料中看到,當堆記憶體被釋放時就發生程式崩潰了。因為我們無法判單堆釋放時發生了什麼情況,所以我們需要開啟完整的堆記憶體頁表來跟蹤堆記憶體的資料變化,命令如下:
YOUR_WINDBG_INSATALL_LOCATION\gflags.exe/p /enable outlook.exe /full
上述命令返回的結果如下,表明命令已成功執行了。
接下來,我們再次開啟Outlook,選擇PoC檔案並監控崩潰發生時新的棧空間情況:
現在我們可以看到,ECX指向的非0記憶體地址時不可讀的,並且在向這個記憶體地址寫入資料時會發生異常,很有可能是因為程式在嘗試向未分配(或未釋放)的記憶體地址寫入資料。我們可以通過檢測記憶體頁分配情況來驗證這種猜想,此時我們會看到記憶體仍然擁有Reserve屬性:
現在我們需要弄清楚,為什麼程式會向未使用的記憶體頁寫入資料。通過靜態分析,我們可以看到ECX的值來自於EDI,而EDI貌似會在程式呼叫MAPIAllocateBuffer後被修改:
靜態分析的結果表明,MAPIAllocateBuffer函式其實是RtlAllocateHeap的封裝函式,而這個函式會確保請求的記憶體大小引數不會超過0x7FFFFFF7。但是,它無法檢測該引數的值是否為0,因為實際分配的堆大小為8位元組,超過了請求的堆大小,這8個位元組填充值為0×0000000001000010。接下來,MAPIAllocateBuffer會返回這8個位元組後面的堆地址。因此,在呼叫MAPIAllocateBuffer之後EDI的值為8 + 分配的堆地址(來自RtlAllocateHeap):
根據上面的靜態分析結果,我們可以大致判斷導致漏洞出現的原因為整型溢位問題。通過調式後我們發現,呼叫MAPIAllocateBuffer時的堆大小引數為0,因為MAPIAllocateBuffer請求分配的堆大小為0+8=8,此時RtlAllocateHeap不會返回錯誤,而是返回正確的堆地址。MAPIAllocateBuffer會使用這8位元組來寫入地址0×0000000001000010,然後把無效的記憶體地址返回給使用者:
接下來,我們需要弄清楚請求的堆大小值為什麼會變成0。原來,0值來自於當前的一個函式引數:arg_4(eax = arg_4 * 4 + 4)。但是,當這個函式被呼叫時,arg_4的值並非傳遞進來的引數值,這也就意味著arg_4的值被修改了。分析後我們發現,罪魁禍首是其子函式sub_65F7DA:
在對子函式sub_65F7DA進行分析後,我們發現它也是一個封裝函式。原來,這個函式是ReadFile,而arg_4得值實際上來自於PoC檔案:
除錯結果表明,arg_4讀取到的檔案內容為0xFFFFFFFF,因此堆記憶體的分配大小就是0xFFFFFFFF * 4 + 4 = 0(整型溢位)。然而,程式並不會檢測這種錯誤,最終導致了越界寫入的情況出現:
在PoC檔案中我們可以看到,並不存在0xFFFFFFFF這個值:
將其修改為0xAABBCCDD後再次進行除錯,我們就可以證實溢位就是由這4個位元組造成的:
在安裝了修復補丁之後,我們對前後的程式程式碼進行了對比,我們發現補丁增加了對請求分配堆記憶體大小的驗證:
因此,廣大使用者請儘快安裝更新補丁以防止攻擊者利用該漏洞實施攻擊。
漏洞資訊
MS.Outlook.CVE-2018-8587.Remote.Code.Execution
* 參考來源: fortinet ,FB小編Alpha_h4ck編譯,轉載請註明來自FreeBuf.COM