研究人員在OEM廠商的外圍設備中發現了多個漏洞,這影響了這些OEM廠商(Razer、EVGA、MSI、AMI)的許多用戶。這些漏洞源於一個眾所周知的易受攻擊的驅動程序,通常被稱為WinIO/WinRing0。
本文會重點介紹一個有趣的TOCTOU漏洞案例(CVE-2022-25637),以及其他一些漏洞。
眾所周知,MSI開發了一個名為MSI Dragon Center的便捷工具,其目的是檢索有關計算機統計信息(即GPU/CPU使用情況)並控制硬件相關設置。
不過從實際反饋來看,它運行得併不好,出現了許多UI問題並且加載時間慢。有研究人員在調整MSI電腦上風扇的速度時,無疑發現了其中的問題,很可能是MSI使用了內核驅動程序。本文的作者檢查證實了MSI使用內核驅動程序來執行Dragon Center提供的一些功能,即風扇控制功能是通過WMI對像或供應商特定的API(如NvAPI_GPU_SetCoolerLevels)完成的,並沒有在Dragon Center代碼中實現。此外,Dragon Center加載了一個名為WinIO的驅動程序,這顯然與風扇控制的邏輯無關。綜合上述事件,我開始研究WinIo驅動程序,因為它可能會構成一個有趣的攻擊面。
WinIO是由www.internals.com開發的著名內核驅動程序(該網站已不再在線,但可以通過archive.org訪問)。 WinIO驅動程序庫允許32位和64位Windows用戶模式進程直接訪問I/O端口、MSR寄存器和物理內存,它已被許多供應商廣泛使用。由於它具有強大的功能,因此責任重大,驅動程序應該只允許特權用戶使用這些功能。
然而,在WinIo中,情況有所不同,任何用戶都可以與之交互,包括沙盒應用程序。 WinIo可以簡單地在設備對像上設置一個安全描述符,以避免低權限用戶與其交互,如下面的代碼片段所示。
將SDDL應用於設備對象
我在我的設備上發現的WinIo版本是驅動程序的早期版本(我們懷疑它是WinIo 2.0版),即使是最簡單的漏洞也極易對其發起攻擊,一個簡單的DeviceIoControl請求可能會破壞堆棧。通過使用具有IOCTL代碼0x80102040的DeviceIoControl發送I/O請求,研究人員得到了一個memmove方法。
WinIo調度函數:易受攻擊的memmove/memcpy
此memmove缺少任何參數檢查。更準確地說,它屬於控制長度參數,該參數源自SystemBuffer。因此,通過指定大於IOPM本地變量長度的長度,我們可以很容易地破壞堆棧。因此,我們可以重寫本地堆棧數據,這是一個經典的緩衝區溢出場景,它可以導致重寫調用方的返回指針,再加上使用ROP鏈,最終導致權限升級。
然而,存在另一個漏洞,即通過物理內存映射的權限升級,這允許我們擁有一個強大的R/W原語。
WinIO中的任意內存R/W函數
此時,會出現一個問題,這個代碼庫是否可以用於其他地方\驅動程序?
尋找其他易受攻擊的程序我們在VirusTotal中編寫了一個相對簡單的查詢,並找到了114個潛在驅動程序的匹配項,這些潛在驅動程序可能與我們的脆弱驅動程序共享相同的代碼庫。
通過快速瀏覽一些驅動程序的逆向代碼,許多供應商似乎使用了WinIo驅動程序的相同易受攻擊的代碼庫。
其中Razer Synapse Service.sys特別引起了我的注意。
Razer Synapse Servicesys VirusTotal結果
三個異常的Razer Synapse研究人員的設備上安裝的是Razer Synapse,RazerSynapse(雷蛇雲驅動)是款雲端軟件,配合Razer的鍵鼠使用,可以把遊戲配置文件、宏,已經鼠標等的設置參數同步到雲端。 Razer Synapse加載了一些驅動程序,其中之一是Razer Synape服務。 sys–具有不同名稱的WinIo驅動程序。通常,當加載WinIo驅動程序時,不會對設備對象設置安全限制。然而,在這種情況下,它有一個限制性的安全描述符。
應用於Razer驅動程序的SDDL
此時,通常應該放棄此驅動程序,即使它是錯誤的,因為為了與此驅動程序交互,你需要具有高權限,這意味著你已經可以執行特權操作。
在Windows中,如果你以admin+的身份開始,那麼讓驅動程序做一些異常的操作並不會被視為是不安全的事情。由於驅動程序沒有設置安全描述符,所以這一定是在其他地方完成的。
根據MSDN的描述:“設備對象的安全性可以由放置在INF文件中或傳遞給IoCreateDeviceSecure的SDDL字符串指定。”
現在,我們應該仔細分析一下INF文件,但令人驚訝的是,並沒有INF文件!
不得不說這是一個很奇怪的情況,我們懷疑Razer Synapse Service.exe將SDDL設置為驅動程序創建的設備對象。為此,我們監控了Procmon中的系統,並註意到該程序負責加載Razer Synapse Service.sys驅動程序。
準備安裝“Razer Synapse Service.sys”
我們需要對Razer Synapse Service.exe進行逆向工程,以了解它在何處應用安全描述符。幸運的是,它是用C#編寫的,這將使我們的逆向工程工作更容易,因為我們可以使用reflector。
通過遍歷模塊列表,找出哪個模塊負責加載內核驅動程序。我們將不同的模塊反編譯回C#(我們使用了DnSpy),然後繼續查找與服務控制管理器(SC管理器)進行的任何通信。我們發現負責此事的模塊是LibreHardwareMonitorLib(開源)。
如果我們仔細觀察代碼,就會發現一些奇怪的東西。
我們可以看到,在第11-14行中,服務嘗試打開驅動程序創建的設備對象的句柄,然後為其設置新的安全描述符。我的意思是,他們在用戶模式下使用了正確的方法,但他們一開始就不應該在用戶模式空間中這樣做。
如上所述,應用SDDL應該在內核中完成,並在設備創建時完成。事實上,它沒有在內核空間中發生,這導致設備對象持有一個默認的安全描述符,該描述符允許低權限用戶與設備對象交互。
這是檢查使用時間漏洞的典型案例。如果我們能夠利用這個短時間段獲取設備對象的句柄,那麼我們就可以濫用WinIo的漏洞。
漏洞利用“Razer Synapse Service”配置為自動啟動。因此,我們不能從低權限用戶的角度隨意重新啟動它。要利用該漏洞,就是要在不重新啟動服務的情況下重新創建競爭條件(race condition)。
事實證明,使用synapse3提供的更新機制,觸發這種情況相對容易。每當安裝新更新或新插件時,Razer Synapse Service將重新啟動。
重新啟動過程包括卸載WinIo驅動程序,然後重新加載。因此,允許我們觸發競爭條件。這是通過安裝一個新模塊來完成的,這一操作不需要特權,因為Synsapse3支持Alexa、Chroma Connect、Chroma Studio、Philips HUE等模塊。
模塊列表Synapse 3
如果我們選擇安裝其中一個模塊,synapse3進程將通過命名管道向Razer Central Service發送命令,以安裝所選模塊。
RazerCentralService.exe啟動模塊安裝,包括停止和啟動RazerSynapse服務,從而卸載和加載驅動程序。為此,我們創建了一個POC,該POC完成了整個過程,在POC觸發模塊安裝期間,一個無限的while循環嘗試使用CreateFile API打開設備對象的句柄。我們設法在安全描述符更改之前打開了設備的句柄,換句話說,我們贏得了競爭。此時,服務更改安全描述符並不重要,因為我們擁有設備對象的有效句柄。
現在我們可以自由地與設備對象交互,可以利用WinIo的一些漏洞。在本文的POC中,我們利用了MSR R/W原語。寫入MSR原語允許我們重寫IA32_LSTAR MSR。這個特定的MSR保存著指向處理系統調用的內核函數的指針(KiSystemCall64Shadow)。通過重寫函數指針,我們可以實現任意的內核代碼執行。
根據@_xeroxz的經驗,我們使用稱為msrexec的工具輕鬆地開發了MSR寫入原語漏洞。
總結這項研究是我們修設備風扇時無意中發現的一個漏洞,通過利用一個很酷的競爭條件,導致在內核中運行代碼。