安全文库

【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)


【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)

anhkgg

【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)

譯者:anhkgg

預估稿費:200RMB

投稿方式:發送郵件至linwei#360.cn,或登陸網頁版在線投稿


傳送門


【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞


簡介


安全服務商和內核開發者需要注意,Windows內核的一個代碼編寫錯誤可以能讓你無法再運行中拿到是哪個模塊被載入了的信息。並且修復它不是你想象的那麼簡單。


快速回顧


在研究windows內核過程中,我們遇到了一個有趣的問題,關於PsSetLoadImageNotifyRoutine,就是通知模塊載入的。在註冊了一個載入PE模塊的通知之後,內核回調函數可能會收到一個不合法的鏡像名字。

在我們之前發布的博客中,我們研究了這個bug相關的不同內核組件。在弄明白了原因之後,我們找到了一種解決它的方法。


疑惑:一個持久的問題


有一件事對我們來說非常奇怪,就是這個機制已經非常老了,但是在我們之前沒有人遇到這個問題。這麼多年來一個文檔化的廣泛使用的windows內核機制怎麼可能這樣,沒有修復這麼一個明顯的問題,或者發布新的文檔。

經過在線的一番與這個bug相關的信息的搜索,我們沒有發現任何官方的文檔,或者可能引起的任何信息。我們也在社區遇到一個類似問題的特殊說明,它讓我們知道了一些重要的事情:

a. 這個問題,我們也可以復現,好像來源於同樣的問題

b. 一個關於回調通知的同樣的bug在十年前甚至更早就已經出現了(我們沒有發現在2001年以前的信息了)

c. 微軟應該也知道這個問題


錯誤的解決方案


在尋找解決這個bug的方案時,我們發現了幾款工具試圖通過不同的方法解決它,但其實沒什麼用。有些使用ObQueryNameString或者各種API其實會有相同的結果,在其他地方簡單增加和FILE_OBJECT.FileName相關的DEVICE_OBJECT的名字,但其實在object的生命周期從來沒有使用它。


我們還在繼續做


此時,我們決定繼續檢查其他提供PE載入回調通知的函數,如PsSetCreateProcessNotifyRoutineEx,這個函數在Windows Vista Sp1之後才能使用。我們想看看他是否也有同樣的bug在內核中。

讓我們困惑的是在這個函數中CreateInfo參數有一個特定flag,FileOpenNameAvailable,當設置為TRUE時,表示這個字元串指定的完整文件名字是要打開的可執行文件的名字。如果設置為FALSE,操作系統只是提供一部分名字。

在查看nt!PspInsertThread的反彙編代碼是,這個flag明顯被設置為FALSE,ImageFileName是FILE_OBJECT(進程的SECTION)的FileName欄位。像我們之前提到的載入鏡像通知回調的問題一樣,這個flag表明這個穿拿來的參數的完整性是不可信任的。

【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)

圖1. Nt!PspInsertThread – 在調用註冊的回調之前初始化CreateInfo.ImageFileName和CreateInfo.FileOpenNameAvailable

看起來微軟像是注意到了這個問題,至少負責PsSetCreateProcessNotifyRoutineEx的開發者注意到了。事實上,微軟為什麼至今也沒有解決PsSetLoadImageNotifyRoutine的bug依然讓人不解。

用微軟的方式(幾乎正確)


在搜索更多關於PsSetCreateProcessNotifyRoutineEx的文檔的時候,我們找到了一篇2007年5月的文檔,叫做「支持Windows Server 2008的內核數據和過濾」,目前已經在微軟的網站上已經沒有了(這裡有引用)。這個文檔指明在使用進程創建回調時,驅動可以通過過濾管理API獲取額外的屬性,比如FltGetFileNameINformationUnsafe

根據這些信息我們確認FltGetFielNameInformationUnsafe可以提供給我們最優雅和簡單的解決這個bug的方案。使用這個函數可以讓我們不用實現文件系統小過濾驅動就可以解決這個問題。我們從PsSetLoadImageNotifyRoutine回調中拿到FILE_OBJECT的方式和從PsSetCreateProcessNotifyRoutineEx回調中非常類似,所以在我們的問題中它看起來是一個可行的解決方案。

讓我們更放心的是在某些Windows自己的組件中也使用了這個函數,比如Windows Defender和防火牆。

 【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)

圖2. Windows 10Redstone中Windows Defender(WdFilter.sys)和防火牆的回調

儘管未盡明


在載入鏡像通知回調中使用FltGetFileNameInformationUnsafe偶爾會失敗,返回STATUS_OBJECT_NAME_NOT_FOUND。在微軟文檔中這個錯誤沒記錄未這個函數可能的錯誤。

經過一些實驗,我們找到能始終重現這個錯誤狀態的準確的事件序列。FltGetFileNameInformationUnsafe會在一定階段調用fltmgr!FltpExpandShortNames,這個是實際驗證文件路徑是否存在的函數。

【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)

圖3. Fltmgr!FltGetFileNameINformationUnsafe中Fltmgr!FltpExpandShortNames的回調

問題是這個驗證僅僅是一部分:代碼驗證路徑中所有目錄是否存在,但是卻忽略了檢查給定路徑中文件本身是否存在。因此,我們現在知道它給出的錯誤代碼只在文件當前不在他以前的目錄中才是有效的,我們至少可以獲取到它打開的名字(在給FltGetFileNameInformationUnsafe傳遞適當的flag的時候)。

因此,我們只有最後一件事需要處理:不管什麼時候FltGetFileNameInformationUnsafe調用成功,我們需要確保拿到的路徑是文件實際存在的。還有,我們需要驗證這個文件是和我們在載入鏡像回調中拿到的文件是同一個。

總結


理論上上一篇博客描述的這個Windows內核的bug,具有潛在的危險,用來欺騙依賴通知機制提供信息的安全產品。這個缺陷看起來來自於一個代碼編寫錯誤,從Windows2000最新的Windows10發布版都會收到影響。這意味著只有微軟修復了這個bug,安全廠商在windows環境中開發的產品不能依賴回調通知提供的錯誤信息。安全廠商必須尋找替代的更可信的方法來獲取通知機制提供的不可靠信息,希望可以用到本博客中提供的研究內容。


【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續) 【技術分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞(續)

本文由 安全客 翻譯,轉載請註明「轉自安全客」,並附上鏈接。
原文鏈接:https://breakingmalware.com/documentation/windows-pssetloadimagenotifyroutine-callbacks-good-bad-unclear-part-2/