自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

攻擊Windows平臺NVIDIA驅(qū)動程序

安全 黑客攻防 網(wǎng)站安全
NVIDIA為每一個逃逸都單獨實現(xiàn)了其私有數(shù)據(jù)(DXGKARG_ESCAPE 結(jié)構(gòu)體中的pPrivateDriverData),格式為“頭部+數(shù)據(jù)”。

[[184593]]

前言

現(xiàn)代圖形驅(qū)動程序是十分復(fù)雜的,它提供了大量有希望被利用的攻擊面,可以使用具有訪問GPU權(quán)限的進(jìn)程(比如Chrome的GPU進(jìn)程)進(jìn)行提權(quán)和沙箱逃逸。在這篇文章中,你們將看到如何攻擊NVIDIA內(nèi)核模式的Windows驅(qū)動程序,以及在此期間我發(fā)現(xiàn)的一些bug。我的這項研究是Project Zero的一個20%項目的一部分,在此期間我總共發(fā)現(xiàn)了16個漏洞。

內(nèi)核WDDM接口

圖形驅(qū)動程序的內(nèi)核模式組件被稱為顯示微端口驅(qū)動程序。微軟的官方文檔為我們提供了一個很好的結(jié)構(gòu)圖,總結(jié)了各個組件之間的關(guān)系:

在顯示微端口驅(qū)動程序 的DriverEntry()函數(shù)中,DRIVER_INITIALIZATION_DATA結(jié)構(gòu)被由廠商實現(xiàn)的函數(shù)(實際上與硬件進(jìn)行交互)的回調(diào)進(jìn)行填充,該函數(shù)通過DxgkInitialize()傳遞給dxgkrnl.sys(DirectX的子系統(tǒng))。這些回調(diào)要么由DirectX內(nèi)核子系統(tǒng)調(diào)用,要么在某些情況下直接從用戶模式代碼調(diào)用。

DxgkDdiEscape

一個眾所周知的潛在漏洞的入口點是 DxgkDdiEscape 接口。它可以直接在用戶模式下被調(diào)用,并且可以接受任意數(shù)據(jù),該數(shù)據(jù)以廠商指定的方式(本質(zhì)上是IOCTL)解析和處理。在后文中,我們將使用術(shù)語“逃逸”來表示由DxgkDdiEscape 函數(shù)支持的特定命令。

截止寫作時,NVIDIA有著數(shù)量驚人的400多個逃逸,所以這里也是我花費了絕大部分時間的地方(這些逃逸中的絕大多數(shù)是否有必要處在內(nèi)核空間中是一個問題):

  1. // (這些結(jié)構(gòu)體的名稱是我命名的) 
  2. // 表示一組逃逸代碼 
  3. struct NvEscapeRecord { 
  4.   DWORD action_num; 
  5.   DWORD expected_magic; 
  6.   void *handler_func; 
  7.   NvEscapeRecordInfo *info; 
  8.   _QWORD num_codes; 
  9. }; 
  10.    
  11. // 有關(guān)特定逃逸代碼的信息 
  12. struct NvEscapeCodeInfo { 
  13.   DWORD code; 
  14.   DWORD unknown; 
  15.   _QWORD expected_size; 
  16.   WORD unknown_1; 
  17. }; 

NVIDIA為每一個逃逸都單獨實現(xiàn)了其私有數(shù)據(jù)(DXGKARG_ESCAPE 結(jié)構(gòu)體中的pPrivateDriverData),格式為“頭部+數(shù)據(jù)”。頭部格式如下:

  1. struct NvEscapeHeader { 
  2.   DWORD magic; 
  3.   WORD unknown_4; 
  4.   WORD unknown_6; 
  5.   DWORD size
  6.   DWORD magic2; 
  7.   DWORD code; 
  8.   DWORD unknown[7]; 
  9. }; 

這些逃逸由32位代碼(上面NvEscapeCodeInfo結(jié)構(gòu)體的第一個成員)標(biāo)識,并根據(jù)它們的最高有效字節(jié)進(jìn)行分組(從1到9)。

在處理每個逃逸代碼之前都會做一些驗證。具體來說,每個 NvEscapeCodeInfo 應(yīng)當(dāng)包含頭部后面的逃逸數(shù)據(jù)的預(yù)期大小。這將根據(jù)NvEscapeHeader中的大小來驗證,NvEscapeHeader自身又通過傳遞給 DxgkDdiEscape的PrivateDriverDataSize字段進(jìn)行驗證。但是,預(yù)期大小有時可能為0(通常當(dāng)逃逸數(shù)據(jù)為可變大小時),這意味著逃逸處理程序負(fù)責(zé)進(jìn)行自身的驗證。這將導(dǎo)致一些bug(1,2)。

在逃逸處理程序中發(fā)現(xiàn)的大多數(shù)漏洞(總共13個)都是些非?;镜腷ug,例如盲目地向用戶提供的指針進(jìn)行寫入操作,向用戶模式公開未初始化的內(nèi)核內(nèi)存以及不正確的邊界檢查。還有許多我發(fā)現(xiàn)的問題(例如OOB讀取)沒有報告出去,因為它們似乎沒有可以利用的地方。

DxgkDdiSubmitBufferVirtual

另一個有趣的入口點是DxgkDdiSubmitBufferVirtual函數(shù),它首次在Windows 10和WDDM 2.0中被引入,主要用來支持GPU虛擬內(nèi)存(而舊的 DxgkDdiSubmitBuffer / DxgkDdiRender 函數(shù)已被棄用)。這個函數(shù)相當(dāng)復(fù)雜,并且還接受來自用戶模式驅(qū)動程序提交的每一個由廠商特定的數(shù)據(jù)。我在這里找到了一個bug。

其他

還有一些其他WDDM函數(shù)接受廠商特定的數(shù)據(jù),但快速瀏覽后沒有發(fā)現(xiàn)任何有趣的東西。

暴露的設(shè)備

NVIDIA暴露了可由任何用戶打開的一些其他設(shè)備:

  1. \\.\ NvAdminDevice 

似乎用于 NVAPI。很多ioctl處理程序似乎都會調(diào)用DxgkDdiEscape。

  1. \\.\ UVMLite {Controller,Process *} 

可能與NVIDIA的“統(tǒng)一內(nèi)存”相關(guān)。在這里找到1個bug。

  1. \\.\ NvStreamKms 

作為GeForce Experience的一部分默認(rèn)選擇安裝,但也可以在安裝期間選擇停用。不是很明白為什么這個驅(qū)動程序是必要的。在這里也發(fā)現(xiàn)了1個bug。

更多有趣的Bug

我發(fā)現(xiàn)的大多數(shù)bug是通過手動逆向和分析得到的,并且使用了一些自定義的IDA腳本。我還寫了一個模糊工具。最終結(jié)果成功得有點令人驚訝,這也說明了這些bug的簡單性。

雖然大多數(shù)bug相當(dāng)無聊(缺乏驗證之類的簡單案例),但也有一些比較有意思。

NvStreamKms

此驅(qū)動程序使用 PsSetCreateProcessNotifyRoutineEx 函數(shù)注冊進(jìn)程創(chuàng)建通知回調(diào)。該回調(diào)檢查系統(tǒng)上創(chuàng)建的新進(jìn)程是否和先前通過發(fā)送IOCTL設(shè)置的映像名稱相匹配。

這個創(chuàng)建通知的例程包含一個bug:

(簡化的反編譯輸出)

  1. wchar_t Dst[BUF_SIZE]; 
  2.    
  3. ... 
  4.    
  5. if ( cur->image_names_count > 0 ) { 
  6.   // info_是傳遞給例程的PPS_CREATE_NOTIFY_INFO 
  7.   image_filename = info_->ImageFileName; 
  8.   buf = image_filename->Buffer; 
  9.   if ( buf ) { 
  10.     filename_length = 0i64; 
  11.     num_chars = image_filename->Length / 2; 
  12.     // 通過掃描反斜杠來查找文件名 
  13.     if ( num_chars ) { 
  14.       while ( buf[num_chars - filename_length - 1] != '\\' ) { 
  15.         ++filename_length; 
  16.         if ( filename_length >= num_chars ) 
  17.           goto DO_COPY; 
  18.       } 
  19.       buf += num_chars - filename_length; 
  20.     } 
  21. DO_COPY: 
  22.     wcscpy_s(Dst, filename_length, buf); 
  23.     Dst[filename_length] = 0; 
  24.     wcslwr(Dst); 

此例程通過向后搜索反斜杠('\')的方法從PS_CREATE_NOTIFY_INFO的ImageFileName 成員中提取映像名稱,然后使用 wcscpy_s 將其復(fù)制到堆棧緩沖區(qū)(Dst),但傳遞的長度是計算出的名稱長度,而不是目標(biāo)緩沖區(qū)的長度。

即使 Dst 是大小固定的緩沖區(qū),這也不能被視為一個直接溢出。因為它的大小大于255個wchar長度,并且對于大多數(shù)Windows文件系統(tǒng)路徑組件來說其不能超過255個字符。而因為ImageFileName 是規(guī)范化的路徑,所以掃描反斜杠在大多數(shù)情況下也是有效的。

然而,上述規(guī)則可以通過如下方式繞過:對于一個符合通用命名規(guī)約(UNC)的路徑,其規(guī)范化后保持以正斜杠('/')作為路徑分隔符(感謝James Forshaw向我指出這一點)。這便意味著我們可以得到一個“aaa / bbb / ccc / ...”形式的文件名從而引發(fā)溢出。

例如:

  1. CreateProcessW(L"\\\\?\\UNC\\127.0.0.1@8000\\DavWWWRoot\\aaaa/bbbb/cccc/blah.exe", …) 

另一個有趣的關(guān)注點是,跟隨受損副本的wcslwr實際上并不限制溢出的內(nèi)容(唯一的要求是有效的UTF-16編碼)。因為計算的filename_length不包含null終止符,所以wcscpy_s 會認(rèn)為目的地太小,然后以在開始處寫入null字節(jié)的方式來清除目的地字符串(發(fā)生在內(nèi)容復(fù)制到 filename_length 字節(jié)之后,因此溢出仍然發(fā)生)。這意味著 wcslwr是無用的,因為對 wcscpy_s的調(diào)用和一部分的代碼從來沒有工作過。

利用這個漏洞就不那么復(fù)雜了,因為驅(qū)動程序沒有使用堆棧cookie編譯過。在以前的漏洞中附加過一個本地特權(quán)提升漏洞利用程序,它配置了一個偽造的WebDAV服務(wù)器來利用漏洞(ROP,從主堆棧到用戶緩沖區(qū),再次ROP來分配 讀寫執(zhí)行內(nèi)存,用來存放shellcode并跳轉(zhuǎn)進(jìn)去)。

UVMLiteController中錯誤的驗證

NVIDIA的驅(qū)動程序還在 \\.\ UVMLiteController路徑中暴露了一個可以由任何用戶打開的設(shè)備(包括從沙箱中的Chrome GPU進(jìn)程)。該設(shè)備的IOCTL處理程序直接將結(jié)果寫入Irp->UserBuffer中,作為將要傳遞給 DeviceIoControl 的輸出指針 (微軟的文檔中指出不要這樣做)。IO控制代碼指定使用METHOD_BUFFERED,這意味著在Windows內(nèi)核檢查地址提供的范圍并將其傳遞給驅(qū)動器之前,用戶具有寫操作的權(quán)限。

然而,這些處理程序還缺少對輸出緩沖區(qū)的邊界檢查,這意味著用戶模式上下文可以通過任何任意地址傳遞值為0的長度(可以繞過ProbeForWrite的檢查), 這樣做的結(jié)果是創(chuàng)造出一個受限的Write-what-where情景(這里的“what“僅限于一些特定的值:包括32位0xffff,32位0x1f,32位0和8位0)。

在原始問題中附加了簡單的提權(quán)漏洞利用 。

遠(yuǎn)程攻擊途徑?

考慮到已發(fā)現(xiàn)的bug數(shù)量如此之眾,我做了一個調(diào)查,是否可以在不必首先破壞沙盒進(jìn)程的前提下,完全從遠(yuǎn)程環(huán)境中訪問其中任意一個bug(例如通過瀏覽器中的WebGL或通過視頻加速)。

幸運的是結(jié)果似乎并非如此。但這并不令人驚訝,因為這里的易受攻擊的API是非常底層的,只有經(jīng)過許多層才能訪問得到(對于Chrome而言,需要經(jīng)歷libANGLE -> Direct3D運行時和用戶模式驅(qū)動程序 ->內(nèi)核模式驅(qū)動程序),并且通常需要在用戶模式驅(qū)動程序中構(gòu)造有效的參數(shù)才能調(diào)用。

NVIDIA的回應(yīng)

發(fā)現(xiàn)的bug的性質(zhì)表明NVIDIA仍有很多工作要做。他們的驅(qū)動程序包含的很多可能不必出現(xiàn)在內(nèi)核中的代碼,而發(fā)現(xiàn)的大多數(shù)錯誤是非常基本的錯誤。事到如今,他們的驅(qū)動程序(NvStreamKms.sys)仍然缺乏非常基本的緩解措施(堆棧cookie)。

不過,他們的反應(yīng)倒是快速且積極的。大多數(shù)bug在截止日期之前已經(jīng)修復(fù)好了,并且他們自己內(nèi)部也在做一些尋找bug的工作。他們還表示,他們一直在努力重構(gòu)他們內(nèi)核驅(qū)動程序的安全性,但還沒有準(zhǔn)備好分享任何具體的細(xì)節(jié)。

時間線

補丁間隔

NVIDIA的第一個補丁,其中包括我報告的6個bug的修復(fù),但是沒有在公告中詳細(xì)說明(發(fā)布說明稱作“安全更新“)。他們原本計劃在補丁發(fā)布后一個月再公布詳細(xì)信息。我們注意到了這一點并告訴他們這樣做并不恰當(dāng),因為黑客可以通過逆向補丁來找到之前的漏洞,而當(dāng)大眾意識到這些漏洞細(xì)節(jié)的時候已經(jīng)晚了。

雖然前6個bug修復(fù)后在30多天內(nèi)都沒有發(fā)布修復(fù)的詳細(xì)信息,但剩余的8個bug的修復(fù)補丁發(fā)布后5天內(nèi)就發(fā)布了細(xì)節(jié)公告??瓷先VIDIA也一直在嘗試減少這種差距,但是就最近的公告來看兩者的發(fā)布仍有很大的不一致性。

結(jié)論

鑒于內(nèi)核中的圖形驅(qū)動程序所暴露出來的巨大攻擊面,以及第三方廠商的低質(zhì)量代碼,它似乎是挖掘沙箱逃逸和特權(quán)提升漏洞的一個非常豐富的目標(biāo)。GPU廠商應(yīng)該盡快將其驅(qū)動代碼從內(nèi)核中轉(zhuǎn)移出去,從而縮小攻擊面使得這種情況得以限制。

責(zé)任編輯:武曉燕 來源: googleprojectzero.blogspot.tw
相關(guān)推薦

2022-05-13 09:14:47

NVidia開源Linux

2021-07-22 23:24:44

Windows 11Windows微軟

2022-05-19 08:33:53

漏洞惡意軟件

2019-10-22 15:40:34

Windows 10驅(qū)動程序Windows

2022-05-23 13:17:32

Linux開源NVIDIA

2015-12-01 10:54:44

Ubuntu 15.1NVIDIA 358.Linux

2018-11-19 10:15:26

Windows 10WiFi驅(qū)動程序

2009-07-03 16:48:05

Windows CE

2019-03-27 13:20:31

Windows 10更新驅(qū)動程序

2009-07-06 18:17:46

JDBC驅(qū)動程序

2009-03-09 18:48:26

Windows 7驅(qū)動開發(fā)

2019-03-11 15:51:25

NVIDIAKepler筆記本

2020-12-20 09:52:44

Windows10操作系統(tǒng)Windows

2023-09-26 19:20:09

微軟開源windows

2018-09-03 15:45:48

Windows 10Windows驅(qū)動程序

2012-11-22 13:49:52

Windows 7

2022-01-10 07:17:02

安全工具CFB模糊測試

2018-07-18 16:35:06

Windows 10Windows驅(qū)動程序

2015-09-10 14:42:37

自動更新UpdateWindows 10

2010-01-07 13:27:22

Linux驅(qū)動程序
點贊
收藏

51CTO技術(shù)棧公眾號