eEye工程介紹:漏洞大曝光 編寫引導(dǎo)層RootKit
原創(chuàng)【51CTO.com 獨(dú)家翻譯】在先前的文章中,我們深入探討了如何通過Windows進(jìn)程處理“特殊”熱鍵,并認(rèn)為主要是通過Win32k.sys中和WINLOGON.EXE進(jìn)程。這一次,我們將努力使用由eEye公司改編的被稱為SysRq的BootRootKit(引導(dǎo)層RootKit)。
更多的信息在eEye公司的bootroot的工程中,演示的相關(guān)幻燈片請到http://www.eeye.com/html/resources/downloads/other/index.html.下載。
SysRq(就是系統(tǒng)需求,它就像鍵盤中的SysRq按鍵)包含一個Kiobyte的引導(dǎo)代碼,加固在Windows自身內(nèi)核中,一旦有本地調(diào)用,它就會先注冊一個特殊熱鍵(control +Shift+SysRq),一旦激活就能打開獲得最高級系統(tǒng)權(quán)限的cmd窗口。盡管這是非常有用的,同時也存在有爭議的系統(tǒng)管理員的工具,它或許會被用在非法的用途中,所以我們目前尚未把它開源。然而,該項(xiàng)目是在一個可行性技術(shù)上進(jìn)行的,如果我們來討論它的技術(shù)細(xì)節(jié)和執(zhí)行時還是很有趣并且很有意義的,這里我們建議讀者要有熟悉Windows內(nèi)核的水平和用戶模式編程的相關(guān)知識。
SysRq 概況
SysRq的要求很簡單:當(dāng)熱鍵被激活后,該引導(dǎo)扇區(qū)代碼才會在系統(tǒng)命令提示符下運(yùn)行。因?yàn)橐龑?dǎo)扇區(qū)代碼,會一直駐守在window內(nèi)核中,但cmd.exe命令是用戶系統(tǒng)最容易的也是最經(jīng)常的調(diào)用。由于很多熱鍵處理由Winlogon完成,因?yàn)樗饕鳛橄到y(tǒng)對開始其他交互式過程處理(例如任務(wù)管理),例如用戶模式代碼就是最合適的主機(jī)進(jìn)程。
正如我們前面提到,在FFDF0000h / 7FFE0000h處的用戶共享數(shù)據(jù)是內(nèi)核空間和用戶空間的橋接,但是實(shí)際上,我們通過使用主機(jī)的用戶代碼來寫入到本地winlogon進(jìn)程空間的地址里面。
我們使用這個實(shí)用技術(shù)來調(diào)用這個代碼,然后我們一直在這個項(xiàng)目中進(jìn)行不斷的修改。在執(zhí)行syerq1.0版本的時候,winxp及更高的版本容易造成藍(lán)屏,我們需要一個更好的解決方法。然而,這是要進(jìn)行多次失敗的嘗試,這些失敗的嘗試看起來還是能給我們帶來一定的受益,它囊括了全部的技術(shù)細(xì)節(jié)。
#p#SysRq1.0版本只能工作在Windows2000系統(tǒng)上
SysRq的第一個階段與BootRootKit的相同,基本三個步驟:
1、安裝一個在Int13h(Bios 磁盤服務(wù))的鉤子;
2、在OSLOADER補(bǔ)丁處并加載其程序;
3、Windows內(nèi)核內(nèi)存使用時要使用一次補(bǔ)丁。
這個問題的第三個步驟是我們只能加載可靠的內(nèi)存尋址模塊。BootRootKit覆蓋在DOS中的的MZ和PE頭NDIS.SYS的代碼之間。因?yàn)樗蒙儆?0h的字節(jié)的代碼植入到內(nèi)核中,但是sysrq持續(xù)更新的代碼要比這遠(yuǎn)遠(yuǎn)大的多,所以我們必須做一些調(diào)整。
SysRq v1.0 也采用了相同的技術(shù),在NTOSKRNL.EXE的DOS 代碼里安裝一個小的PspInitializeSystemDll 鉤函數(shù),但是這只是第一步。臨時的鉤函數(shù)代碼通常映射在常規(guī)存儲器的頁里,并包含在SysRq的虛擬地址0處,通過修改固定的第一個頁表的的C00000000h虛擬地址而進(jìn)入。將SysRq復(fù)制到用戶共享數(shù)據(jù)未用的FFDF0800h處,然后我們接著用鉤函數(shù)替換原先的函數(shù),以便我們更好的執(zhí)行我們的代碼。
我們的目標(biāo)是要取代NTDLL.DLL的地址 !
LdrInitializeThunk,是我們已知的內(nèi)核函數(shù),用我們已知的初始化代碼,它在用戶態(tài)的每個進(jìn)程里的用戶共享數(shù)據(jù)里面,在7FFE0000h處NTOSKRNL初始化代碼的通過我們叫做PspLookupsystemdllEntrypoint函數(shù)并且使用"LdrInitializeThunk"的字符串獲得這個地址。我們發(fā)現(xiàn)這個call指令通過先搜索這個字符串,然后這個鉤子函數(shù)再調(diào)用它自身而不是直接調(diào)用PspLookupsystemDllEntryPoint函數(shù),我們只是想取代LdrInitializeThunk函數(shù)。(其他的NTDLL出口也使用這個函數(shù),包括KiUserApcDispatcher 和KiUserExceptionDispatcher)。
鉤子函數(shù)通過原函數(shù)調(diào)用,然后用一個指向我們在用戶代碼共享處的指針替換掉LdrInitializeThunk函數(shù)指針。當(dāng)然,我們必須保持原來的指針能正常使用,以便完成我們自定義的初始化代碼。
這個代碼就是是SysRq的核心。每一個新線程都要先通過異步過程調(diào)用,這是非常完美的設(shè)計(jì)。因?yàn)槲覀兿胍覀兊拇a執(zhí)行在每一個進(jìn)程中,但是只能有一個winlogon生效,一個最簡單的方法就是不讓winlogon專門試圖訪問Windows內(nèi)核。然而我們只是希望我們的代碼運(yùn)行在進(jìn)程初始化,而不是在每一個線程的初始化,但是我們不能在用戶模式下對這個掛鉤。一個簡單的方法就是檢查加載數(shù)據(jù)是否在[PEB+0Ch]處,
如果為非null,那說明這個進(jìn)程已經(jīng)初始化,我們的代碼不再做任何的操作。
當(dāng)?shù)竭_(dá)進(jìn)程初始化之前,我們的代碼繼續(xù)搜索這個應(yīng)用映像的unicode字符串的“SAS 窗口類,如果我們找到了它,那么接著在RegisterClassw調(diào)用中找到了這個字符串后并創(chuàng)建這個類。那時,我們找到SASWndProc,這個窗口存放類-通過檢索在這個vWNDCLASS.LpfnWndProc之前的存儲地址記錄,然后我們鉤住這個典型函數(shù)的入口點(diǎn)的修改。
我們的SASWndProc函數(shù)構(gòu)造的盡可能的簡單-我們假定能替換PUSH EBP/MOV EBP/SUB ESP (值小于等于800h)這些指令,通過檢查MOV EDI,EDI"來檢查最近新增加的Service Packs例如Windows XP的SP2.為了安裝這個鉤子,我們用這個代碼寫入正在使用的ZwProtecVirtualMemory函數(shù)中,然后在植入到相對應(yīng)的prolog函數(shù),并給SAS window發(fā)一條信息。
該鉤子函數(shù)的行為就像一個非?;镜腟ASWndProc函數(shù),因?yàn)槲覀冇肬SER32.DLL來注冊我們的熱鍵。RegistrHotKey接收到WM_CREATE 信息,并處理這個熱鍵,當(dāng)WM_HOTKEY 信息傳達(dá)到‘idHotKey'我們這個指定的值。顯而易見,當(dāng)我們檢查RegisterHotKey,我們需要USER32.DLL的基址,但是它可以通過在PEB+2Ch的USER32DispatchRoutine指針來獲得標(biāo)記,直到讓我們發(fā)現(xiàn)MZ和PE頭。
當(dāng)按Ctrl + SHIFT +SysRq熱鍵被按下時,我們的WM_HOTKEY創(chuàng)建了一個“cmd”的進(jìn)程并返回到SASWndProc的調(diào)用,并完全中斷原來函數(shù)調(diào)用。實(shí)際上,只有少數(shù)的api調(diào)用涉及到這樣的工作,更多的獲得了窗口駐留和當(dāng)前桌面,因此我們可以得到一個命令shell甚至能鎖定或搶先登陸系統(tǒng)。
工作順序如下:
GetProcessWindowstation() GetUserObjectInformationA(hWinSta, UOI_NAME) OpenInputDesktop(0, FALSE, 0) GetUserObjectInformationA(hDesktop, UOI_NAME) CloseDesktop() |
一旦我們把構(gòu)造好的“WindowsStation\Desktop”字符串填充到'lpDesktop'區(qū)域里一個啟動信息結(jié)構(gòu)中,我們把這個過程叫做
CreateProcessA,并用CloseHand來對它們進(jìn)行清理,那么我們就已經(jīng)大功告成。用戶現(xiàn)在就會擁有一個系統(tǒng)權(quán)限下的command shell。
正如前面文章提到的,這個方法不能應(yīng)用在Windowsxp或更高版本的WIN操作系統(tǒng)上。當(dāng)激活Windows產(chǎn)品以后,它就會驗(yàn)證WINLOGON.EXE在內(nèi)存中的映像,一旦發(fā)現(xiàn)被篡改,它就會自動中斷該進(jìn)程,造成藍(lán)屏而最終導(dǎo)致系統(tǒng)崩潰。雖然我們試圖用其他的代碼來攻擊或者更改,以及對其他的目標(biāo)下鉤子,使得我們能夠再下鉤子以后,用代碼騙過驗(yàn)證,這一操作之后,讓系統(tǒng)認(rèn)為這與之前的系統(tǒng)并沒有任何變化,并沒有對系統(tǒng)中的目標(biāo)下了鉤子。奔著這個目的我們一直使用其他的方法來完成,最終我們發(fā)布了SysRq2.0版本。
#p#SysRq2.0版本開始支持Windows2000,xp,以及2003操作系統(tǒng)
同BootRootKit(引導(dǎo)型rootkit)一樣,SysRq2.0版本也安裝在了INT13h這個硬指令中斷上,對啟動時的OSLOADER.EXE進(jìn)行補(bǔ)丁操作,并對其下了鉤子,最終達(dá)到直接滲透到Windows內(nèi)核。像SysRq1.0一樣,它也是對Winlogon 的SASWndProc進(jìn)行替換操作,但現(xiàn)在的這個版本的技術(shù)實(shí)現(xiàn)與前一版本有著很大的區(qū)別。我們不能改變WINLOGON.EXE映像,但是我們可以通過對窗口類的注冊機(jī)制進(jìn)行攻擊,從而來對它進(jìn)行改變。
USER32.DLL的RegisterClassW 是RegisterClassExWOWW函數(shù)的一個封裝,經(jīng)過一番探索后,我們在WIN32K.SYS中發(fā)現(xiàn)了一個具有同樣作用并且函數(shù)名也一樣的系統(tǒng)調(diào)用的user32函數(shù),它就是NtUserRegisterClassExWOW函數(shù)。由于SysRq工作在核心態(tài),可以直接對WIN32K.SYS下鉤子,但是我們在執(zhí)行內(nèi)核代碼時,不能對已經(jīng)初始化的NTOSKRNL進(jìn)行操作,我們卻可以從進(jìn)程中SMSS.EXE加載的WIN32K.SYS進(jìn)行操作。
這是比其他解決方法更有效的辦法。當(dāng)WIN32K.SYS初始化時,它必須調(diào)用KeAddSystemServieceTable來為用戶以及GDI系統(tǒng)程序提供注冊。通過對這個函數(shù)進(jìn)行下鉤子操作,并更快更好的把它加載到執(zhí)行的WIN32K.SYS中,同時我們使用免費(fèi)的系統(tǒng)服務(wù)表(_W32pServiceTable)和相應(yīng)的參數(shù)表 (_W32pArgumentTable)。像SysRq1.0版本一樣,使用這個鉤子來對NTOSKRNL的頭的DOS代碼處來執(zhí)行一個小stub,然后我們拷貝這個重置的SysRq代碼到用戶共享數(shù)據(jù)里面來進(jìn)行恢復(fù)并執(zhí)行該代碼。
我們對KeAddSystemServiceTable下鉤子主要是通過掛鉤NtUserRegisterClassExWOW這個系統(tǒng)調(diào)用函數(shù)來實(shí)現(xiàn)的,因?yàn)槟莻€函數(shù)沒有輸出,因此需要一點(diǎn)更復(fù)雜的操作。針對這個問題,我們的答案是通過對在W32pServiceTable的代碼進(jìn)行逐個函數(shù)掃描,直到找到NtUserRegisterHotkey,這是唯一的選擇,因?yàn)椤癋FFF7FF0H”那個最容易辨認(rèn)的簽名是用來檢查禁止修改的標(biāo)記。我們知道NtUserRegisterHotkey總是被應(yīng)用到四個程序中,為了安全起見,我們還需要讓W(xué)32pServiceTable這個函數(shù)入口點(diǎn)能被寫入10h字節(jié)的內(nèi)容,。
我們都知道這個函數(shù)位置在系統(tǒng)服務(wù)表里,我們對NtUserRegisterClassExWOW函數(shù)從前到后逐個字母進(jìn)行比對搜索。這是找打它的最好的辦法,或者取6或者7(18h或者1Ch字節(jié))來決定Windows版本。一旦發(fā)現(xiàn)這個函數(shù),我們就替換掉WIN32K系統(tǒng)表的入口并用一個指針指到我們自己的鉤子函數(shù)處,最終替換掉原先這個函數(shù)的指針,并從已恢復(fù)運(yùn)行的KeAddSystemServiceTable中脫掉鉤子。
該NtUserRegisterClassExWOW鉤子函數(shù)并不復(fù)雜,它只用來比較這個類的名稱(都2個參數(shù)與一個unicode字符串指針)和SAS Windows class來完成匹配,它用我們在用戶映射的用戶共享數(shù)據(jù)中的那個更換過的SASWndProc代碼來替換掉‘lpfnWndProc領(lǐng)域中的WNDCLASSEXW結(jié)構(gòu),替換完后再把在PEB特定位置的原始函數(shù)指針進(jìn)行存儲操作。我們要進(jìn)行輸入驗(yàn)證,畢竟我們不希望發(fā)生內(nèi)核漏洞。
最后,我們最終的目的是獲得系統(tǒng)的shell,獲得最高的系統(tǒng)權(quán)限。
SysRq 2.0有一個明顯的缺陷,它只能在支持終端服務(wù)系統(tǒng)上的命令行回話中工作——這個原因是由于每個回話都有自己Win32k全局?jǐn)?shù)據(jù)內(nèi)存的拷貝,包括存儲_W32pServiceTable的.data區(qū)域,可能這就是終端服務(wù)能夠使用Win32k.sys訪問全局變量的原因(感謝eEye工程師Robert Ross指出這一點(diǎn))SysRq的未來版本中,可能會通過直接鉤掛NtUserRegisterClassExWOW代碼來克服這一缺陷,這個改進(jìn)將可以影響到所有的終端服務(wù)回話。
#p#總結(jié):
在這篇文章里,我們已經(jīng)討論我們怎樣實(shí)現(xiàn)SysRq,eEye按照需求提供一個基于BootRoot的實(shí)用程序系統(tǒng)來實(shí)現(xiàn)獲得SYSTEM shell的技術(shù)細(xì)節(jié)。為了了解Windows hotkeys是如何工作的,以便使得在任何臺式機(jī)上都能支持WinLogon 系統(tǒng)進(jìn)程來完成熱鍵注冊,我們進(jìn)行了相關(guān)逆向工程操作。
詞匯注釋:
1、WinLogon登錄管理
Winlogon進(jìn)程負(fù)責(zé)管理登錄相關(guān)的安全性工作,它負(fù)責(zé)處理用戶的登錄與注銷、啟動用戶shell、輸入口令更改口令、鎖定與解鎖工作站等。Winlogon進(jìn)程必須保證其與安全相關(guān)操作對其他進(jìn)程不可見,以免其他進(jìn)程取得登錄密碼。
系統(tǒng)初始化時,啟動用戶程序之前,Winlogon進(jìn)行特定工作已保障以上的需求。Winlogon進(jìn)程將創(chuàng)建并打開一個Window Stations,然后設(shè)置一個訪問控制人口(ACE),該ACE中只包含Winlogon進(jìn)程的SID,這樣就只有Winlogon進(jìn)程才能訪問該Window Stations 。然后winlogon創(chuàng)建桌面,設(shè)置其中的winlogon桌面,只有winlogon可以訪問,其他進(jìn)程不能訪問該桌面的任何數(shù)據(jù)和代碼;利用這一特性保護(hù)口令、鎖定桌面等操作的安全。winlogon還會注冊安全注意序列(SAS - secure attention sequence)的熱鍵,任何時候按下SAS熱鍵(缺省為ctrl+alt+del),將調(diào)用Winlogon,切換到安全桌面,從而使密碼捕捉程序不能接收登錄密碼和更改密碼等安全活動。
2、涉及函數(shù)解釋
NtQueryDirectoryFile
在WINNT里在某些目錄中尋找某個文件的方法是枚舉它里面所有的文件和它的子目錄下的所有文件。文件的枚舉是使用NtQueryDirectoryFile函數(shù)。
KeAddSystemServiceTable
函數(shù)KeAddSystemServiceTable允許Win32.sys和其他設(shè)備驅(qū)動程序添加系統(tǒng)服務(wù)表。除了Win32k.sys服務(wù)表外,使用KeAddSystemServiceTable添加的服務(wù)表會被同時復(fù)制到 KeServiceDescriptorTable和KeServiceDescriptorTableShadow中去。
【51CTO.COM 獨(dú)家翻譯,轉(zhuǎn)載請注明出處及譯者!】
【編輯推薦】
原文:Source: Derek Soeder,Software Engineer,http://www.eeye.com/html/resources/newsletters/vice/VI20051104.html
【編輯推薦】