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