摘要:本文描述了一種檢測(cè)內(nèi)核與用戶級(jí)rootkit的新技術(shù).此技術(shù)利用處理器的單步執(zhí)行模式,來(lái)測(cè)定系統(tǒng)內(nèi)核與DLL中執(zhí)行指令的數(shù)量,從而達(dá)到檢測(cè)rootkit和后門(mén)的目的.同時(shí)還討論了其在Win2k下的代碼實(shí)現(xiàn).
--背景知識(shí)
一個(gè)在計(jì)算機(jī)安全領(lǐng)域中重要的問(wèn)題是,如何判斷給定的主機(jī)是否已被入侵.由于以下兩點(diǎn)這項(xiàng)工作變的非常困難:
1.攻擊者可以利用未知漏洞進(jìn)入系統(tǒng).
2.當(dāng)進(jìn)入系統(tǒng)后,入侵者可通過(guò)安裝rootkit和后門(mén)來(lái)隱藏自身(例如:隱藏進(jìn)程,通訊渠道,文件等).本文將集中討論在Win2K系統(tǒng)下rootkit的檢測(cè)問(wèn)題.
--傳統(tǒng)rootkit檢測(cè)技術(shù)中的一些問(wèn)題
傳統(tǒng)的rootkit檢測(cè)程序(那些我們經(jīng)常在UNIX系統(tǒng)中見(jiàn)到的)只能檢測(cè)一些已知的rootkit(這點(diǎn)使它變的像反
病毒程序)或進(jìn)行一些內(nèi)核存儲(chǔ)的掃描.例如Linux中就有一些工具掃描內(nèi)核中的syscall table.這顯然不夠好,因?yàn)橐呀?jīng)有了很多并不更改syscall table的rootkit,而Win2k下也可開(kāi)發(fā)出類似的rootkit.
那檢測(cè)程序是不是還應(yīng)該掃描內(nèi)核代碼
空間?這樣我們就有了一個(gè)運(yùn)行在內(nèi)核模式中的Tripwire.但這還不夠好,因?yàn)樵诖蠖鄶?shù)的操作系統(tǒng)中,我們可以寫(xiě)出即不更改SST(syscall table)也不更改代碼的內(nèi)核級(jí)rootkit.在系統(tǒng)中有很多可以勾連的函數(shù)指針(例見(jiàn)[2]).
以我看,存儲(chǔ)掃描技術(shù)決不會(huì)成為rootkit檢測(cè)的終結(jié).這主要是因?yàn)槲覀儾荒艽_定具體的監(jiān)測(cè)存儲(chǔ)區(qū)域.
那到底怎樣檢測(cè)出我們系統(tǒng)中的入侵者呢?
首先我們以rootkit中所使用的技術(shù),將其分為兩類:
*通過(guò)更改系統(tǒng)結(jié)構(gòu)來(lái)隱藏某對(duì)象的(如運(yùn)行的進(jìn)程)和
*更改內(nèi)核執(zhí)行路徑(例:勾連那些負(fù)責(zé)枚舉活動(dòng)進(jìn)程的內(nèi)核函數(shù))來(lái)達(dá)到同樣目的的.
--更改系統(tǒng)數(shù)據(jù)結(jié)構(gòu)的rootkit
這類的rootkit不太多.有意思的例子包括fu rootkit(見(jiàn)[3]),通過(guò)刪除內(nèi)核中PsActiveProcessList鏈上的進(jìn)程對(duì)象來(lái)隱藏進(jìn)程.ZwQuerySystemInformation等函數(shù)是不能發(fā)現(xiàn)這些隱藏進(jìn)程的.但同時(shí),因?yàn)閃indows的線程分派器(dispatcher, scheduler)使用另外的數(shù)據(jù)結(jié)構(gòu),這些"隱藏"進(jìn)程仍可運(yùn)行(被分配到CPU使用時(shí)間).Windows的線程分派器使用以下三個(gè)(注1)數(shù)據(jù)結(jié)構(gòu):
*pKiDispatcherReadyListHead
*pKiWaitInListHead
*pKiWaitOutListHead
后兩個(gè)是處于"等待"狀態(tài)的線程鏈頭.他們之間稍有不同,但對(duì)我們來(lái)說(shuō)并不重要.
從上面的信息我們可以找到一種檢測(cè)隱藏進(jìn)程的方法.及讀取線程分派器使用的數(shù)據(jù)結(jié)構(gòu),而不是PsActiveProcessList.
當(dāng)檢測(cè)rootkit時(shí)我們應(yīng)該盡可能的觸及更底層的內(nèi)核數(shù)據(jù)結(jié)構(gòu).
有一點(diǎn)應(yīng)該注意,直接從線程分派器使用的鏈中刪除要隱藏的進(jìn)程是不可能的,因?yàn)殡[藏的進(jìn)程將分配不到CPU使用時(shí)間.
--更改執(zhí)行路徑的rootkit
這類的rootkit較為普及.他們通過(guò)修改或增加內(nèi)核或系統(tǒng)DLL中的指令來(lái)達(dá)到目的.檢測(cè)這類rootkit的問(wèn)題是,我們不知道rootkit在什么地方做了那些修改.它可以勾連DLL中的函數(shù),系統(tǒng)服務(wù)列表(System Service Table),改變內(nèi)核函數(shù)的內(nèi)容或修改內(nèi)核中一些奇怪的函數(shù)指針.
--執(zhí)行路徑分析(Execution Path Analysis)
EPA關(guān)注這樣一個(gè)事實(shí):如果入侵者通過(guò)修改執(zhí)行路徑隱藏了一些對(duì)象,那么當(dāng)調(diào)用一些典型的系統(tǒng)和庫(kù)的函數(shù)時(shí),系統(tǒng)將運(yùn)行一些多余的指令.
舉個(gè)例子,如果入侵者為了隱藏文件和進(jìn)程而修改了ZwQueryDirectoryFile()和ZwQuerySysteminformation(),那樣和干凈的系統(tǒng)相比,這些系統(tǒng)函數(shù)就會(huì)執(zhí)行更多的指令.不管入侵者采用勾連或在代碼中加入jmp指令,或其他任何方法.指令增加的原因是rootkit必須進(jìn)行它的任務(wù)(在這個(gè)例子中是隱藏文件和進(jìn)程).
但是Windows 2000的內(nèi)核是一個(gè)非常復(fù)雜的程序,即使在干凈的系統(tǒng)中,某些系統(tǒng)函數(shù)每次運(yùn)行的指令個(gè)數(shù)也是不同的.然而我們可以用統(tǒng)計(jì)學(xué)來(lái)解決這個(gè)問(wèn)題.但首先,我們需要一種測(cè)定指令個(gè)數(shù)的方法......
--指令計(jì)數(shù)器的實(shí)現(xiàn)
單步執(zhí)行模式是Intel處理器的一個(gè)好的特性,我們可以用它來(lái)實(shí)現(xiàn)指令計(jì)數(shù).當(dāng)處理器處在這個(gè)模式時(shí),每執(zhí)行完一條指令,系統(tǒng)將產(chǎn)生一個(gè)除錯(cuò)異常(debug exception, #DB).要進(jìn)入這個(gè)模式,需要設(shè)置EFLAGS寄存器中的TF位(詳見(jiàn)[6]).
當(dāng)執(zhí)行int指令時(shí),處理器會(huì)自動(dòng)清TF位并進(jìn)行權(quán)限切換.這意味著,如果要進(jìn)行內(nèi)核模式下的指令計(jì)數(shù),則必須在中斷處理程序開(kāi)頭設(shè)置TF位.因?yàn)槲覀儗⒁獪y(cè)定一些系統(tǒng)服務(wù)中的指令個(gè)數(shù),勾連中斷向量0x2e,也就是Windows 2000下的系統(tǒng)服務(wù)調(diào)用門(mén)會(huì)變得很有效.
但是,因?yàn)榇嬖谟脩裟J降膔ootkit,也應(yīng)該測(cè)定在ring3級(jí)運(yùn)行的指令個(gè)數(shù).只要在用戶模式下設(shè)置TF位一次就可以了,從內(nèi)核返回時(shí),處理器會(huì)自動(dòng)恢復(fù)這一位.
以上的計(jì)數(shù)方法通過(guò)內(nèi)核驅(qū)動(dòng)器實(shí)現(xiàn).如圖2所示,驅(qū)動(dòng)加載后勾連IDT 0x1和0x2e.為和用戶級(jí)程序交互.驅(qū)動(dòng)勾連一個(gè)系統(tǒng)調(diào)用,用戶級(jí)程序通過(guò)這個(gè)特定的系統(tǒng)調(diào)用來(lái)開(kāi)關(guān)計(jì)數(shù)器.
--一些測(cè)試
我們可以使用上一段中描述的方法來(lái)測(cè)定任意系統(tǒng)服務(wù)中執(zhí)行的指令個(gè)數(shù).
例如,來(lái)檢查是否有人試圖隱藏任意文件,我們可以開(kāi)始一個(gè)簡(jiǎn)單的測(cè)試:
pfStart();
FindFirstFile("C:\\WINNT\\system32\\drivers", &FindFileData);
int res = pfStop();
如果有rootkit隱藏任意文件,則執(zhí)行的指令數(shù)要比干凈的系統(tǒng)多.
如果運(yùn)行這個(gè)測(cè)試上百次,并計(jì)算執(zhí)行指令數(shù)的平均值,我們會(huì)發(fā)現(xiàn)這個(gè)值是非常不確定的.考慮Win2k的復(fù)雜性,這一點(diǎn)也不讓人吃驚.但對(duì)于我們的檢測(cè)目的來(lái)說(shuō),這種現(xiàn)象是不能接受的.但如果我們將得到的那些值的頻率分布用條形圖表示出來(lái),會(huì)發(fā)現(xiàn)圖中有一個(gè)明顯的頻率高點(diǎn).如圖4和5中所表示那樣的,即使是在系統(tǒng)負(fù)載很大時(shí),頻率高點(diǎn)所對(duì)應(yīng)的數(shù)值保持不變.很難解釋這個(gè)令人吃驚的現(xiàn)象,可能是因?yàn)樵谘h(huán)中同一個(gè)系統(tǒng)服務(wù)被調(diào)用幾百次后,與這個(gè)系統(tǒng)服務(wù)相關(guān)的緩沖最后會(huì)被填入固定的值.
假想現(xiàn)在有人安裝了隱藏文件的rootkit,如果我們重復(fù)測(cè)試并繪制相應(yīng)的條形圖,就會(huì)發(fā)現(xiàn)頻率高點(diǎn)向右移了,這是因?yàn)閞ootkit需要進(jìn)行隱藏文件的工作.
在現(xiàn)在的代碼實(shí)現(xiàn)中,只進(jìn)行了少量的測(cè)試,包括典型的服務(wù)如:文件系統(tǒng)讀取,枚舉進(jìn)程,枚舉注冊(cè)表項(xiàng)以及Socket讀取.
這些測(cè)試將有效地檢測(cè)出著名的NTRootkit(見(jiàn)[1]),或最近比較流行的Hacker Defender(見(jiàn)[4]),包括它自帶的網(wǎng)絡(luò)后門(mén),當(dāng)然還包括很多其他的后門(mén).但要檢測(cè)出一些更好的后門(mén)還要加入一些新的測(cè)試.
--誤報(bào)和執(zhí)行路徑跟蹤
雖然對(duì)頻率高點(diǎn)的檢測(cè)有助于我們處理系統(tǒng)的不確定因素,但有時(shí)會(huì)發(fā)現(xiàn)測(cè)試得到的值有小的差值,一般來(lái)說(shuō)不大于20.
有時(shí)這會(huì)是一個(gè)很?chē)?yán)重的問(wèn)題,因?yàn)槲覀儾荒艽_定那些多出來(lái)的指令意味著被入侵或只是正常的誤差.
為解決這個(gè)問(wèn)題,我們使用了執(zhí)行路徑記錄模式.和單一的EPA模式比較,系統(tǒng)增加了對(duì)執(zhí)行路徑的記錄(包括地址和運(yùn)行的指令),首先,系統(tǒng)記錄下正常情況下的執(zhí)行路徑,以后的每一次運(yùn)行將產(chǎn)生diff文件(正常系統(tǒng)和現(xiàn)行系統(tǒng)之間的比較).
我們應(yīng)該使用好的反編譯器來(lái)分析那些不一樣的地方,以此判定他們是否可疑.圖6是一個(gè)diff文件的例子.
現(xiàn)階段的diff文件只記錄下指令的地址,以后可能將兩次測(cè)試的不同結(jié)果存為PE格式文件,并可用IDA等工具分析.
--檢測(cè) ”offset-in-the-code” 的變化
想象有這樣一個(gè)rootkit,它基本和上面提到的 fu rootkit (見(jiàn)[3]) 一樣,但不從PsActiveProcessList中,而是從分派器使用的數(shù)據(jù)結(jié)構(gòu)中移除進(jìn)程.我說(shuō)過(guò)那不可能,因?yàn)殡[藏的進(jìn)程將分配不到運(yùn)行時(shí)間......
然而,rootkit可以同時(shí)更改分派器代碼中所使用數(shù)據(jù)結(jié)構(gòu)的地址(offset),換句話說(shuō),就是使其使用不同的鏈表.但只有分派器使用這個(gè)”新的” 鏈表,而系統(tǒng)其他地方還是使用”舊的”鏈表...... (見(jiàn)圖7).
雖然這種技術(shù)不會(huì)改變執(zhí)行指令的個(gè)數(shù),我們還是能檢測(cè)到它,但需要進(jìn)一步的完善現(xiàn)有的工具.這項(xiàng)功能現(xiàn)在還沒(méi)有實(shí)現(xiàn),但應(yīng)該不是很難.
--針對(duì)EPA的攻防
我們可以想到一些能騙過(guò)EPA類檢測(cè)工具的方法,先把它們分為兩類.
1. 針對(duì)特定工具的欺騙
2. 對(duì)EPA類技術(shù)的通用攻擊
首先,我們考慮一下通用的攻擊方法和怎樣防止這類攻擊.接著討論針對(duì)特定工具的攻擊以及怎樣通過(guò)多態(tài)來(lái)預(yù)防.
--對(duì)EPA類技術(shù)的通用攻擊
首先,惡意程序可以勾連包含除錯(cuò)處理程序(debug handler)地址的IDT入口1,這樣將暫停記錄運(yùn)行的指令數(shù).當(dāng)它完成工作時(shí),再恢復(fù) IDT入口1.這樣rootkit中所執(zhí)行的指令數(shù)不會(huì)被記錄.
我們可以使用intel的除錯(cuò)寄存器來(lái)防止這類的攻擊.可以使用DR0和DR1寄存器對(duì)IDT入口1進(jìn)行寫(xiě)保護(hù).并且為防止rootkit向除錯(cuò)處理程序的開(kāi)始處寫(xiě)入Jmp指令,還需對(duì)其進(jìn)行讀保護(hù).換句話說(shuō),我們不想讓rootkit發(fā)現(xiàn)除錯(cuò)處理程序的地址.但單純對(duì)IDT入口進(jìn)行讀保護(hù)是不行的,系統(tǒng)會(huì)藍(lán)屏.但有一簡(jiǎn)單的解決方法,就是增加額外的一層.見(jiàn)圖9.
還有一種攻擊的方法,在rootkit運(yùn)行時(shí),其將TF位清零,并在惡意操作完成時(shí)恢復(fù)TF位,這樣檢測(cè)工具也只能發(fā)現(xiàn)運(yùn)行的指令數(shù)和正常的系統(tǒng)有細(xì)微差別.
另外,rootkit還能檢查T(mén)F位, 如發(fā)現(xiàn)被跟蹤,則不進(jìn)行惡意操作.這種行為并不會(huì)影響rootkit的正常工作,因?yàn)橹挥斜粰z測(cè)的進(jìn)程才被設(shè)置TF位.
我們可以防止這種攻擊,應(yīng)該注意到的是運(yùn)行每一個(gè)系統(tǒng)指令前,都會(huì)運(yùn)行我們的除錯(cuò)處理程序.以下是簡(jiǎn)單的防預(yù)方法:
如果除錯(cuò)處理程序發(fā)現(xiàn)上一個(gè)運(yùn)行指令是pushf(將EFLAGS寄存器壓入堆棧),則運(yùn)行如下操作.
and [esp], 0xfffffeff;
及清TF位.同樣,如果下一條指令是popf(從堆棧載入EFLAGS的值),則運(yùn)行如下操作.
or [esp],0x100;
及設(shè)TF位.這樣rootkit就不能更改TF位.
這樣的預(yù)防幾乎可夠了,但還不充分.Rootkit仍能以以下方法發(fā)現(xiàn)其被跟蹤:
setTFbit();
if (checkTFbit()!=1) {
//we are traced!
}
所以我們需要更改反檢測(cè)部分的操作,使其可以記錄TF位有沒(méi)有被rootkit更改(比如增加一個(gè)TFbitset變量).
popf/pushf不是存取EFLAGS寄存器的唯一指令,其它像iret/int等指令也可以[注2],因此還要加入對(duì)這些指令的檢測(cè).
對(duì)EGLAGS寄存器的防護(hù)部分還沒(méi)有被實(shí)現(xiàn).一部分原因是通過(guò)對(duì)diff文件的分析也可以發(fā)現(xiàn)這類攻擊.但以后會(huì)增加相應(yīng)代碼.
--對(duì)特定工具的攻擊
如果攻擊者了解關(guān)于特定檢測(cè)工具的一切,他會(huì)有很多種欺騙的手段.比如,可以更改保存指令數(shù)的那個(gè)變量.
不過(guò)這類攻擊具有很強(qiáng)的針對(duì)性,如果有很多不同(或非單一版本)的EPA類工具,這樣的攻擊將不會(huì)有效.
當(dāng)然,我們還是希望可以阻止這類攻擊,強(qiáng)大的多態(tài)代碼生成器可能是唯一的方法.當(dāng)管理員安裝檢測(cè)工具是,會(huì)產(chǎn)生一個(gè)獨(dú)特的內(nèi)核驅(qū)動(dòng)和測(cè)試程序.
多態(tài)代碼生成器部分還沒(méi)有被實(shí)現(xiàn).
--相關(guān)工作
像文章開(kāi)頭所述,筆者還沒(méi)有發(fā)現(xiàn)任何對(duì)rootkit的檢測(cè)方法,不是基于存儲(chǔ)掃描的.
EPA技術(shù)并不被OS所局限,筆者在linux下也實(shí)現(xiàn)了一相關(guān)工具,參5中有對(duì)其的詳述以及簡(jiǎn)單的代碼實(shí)現(xiàn).
References
[1] Greg Hoglund, et al, ROOTKIT home, telnet://rootkit.com,
[2] palmers, Sub proc_root Quando Sumus, Phrack Magazine, issue 58, 2001.
[3] fuzen_op, fu rootkit, telnet://rootkit.com,
[4] Holy Father, Hacker Defender Home, http://rootkit.host.sk,
[5] Jan Rutkowski, Execution path analysis, Phrack Magazine, issue 59, 2002.
[6] IA-32 Intel Architecture Software Developer’s Manual, vol1-3.
注1: 作者相信這三個(gè)鏈表包含了系統(tǒng)中所有的線程.但還需進(jìn)一步研究.