資源描述:
《緩沖區(qū)溢出原理及防范》由會員上傳分享,免費在線閱讀,更多相關(guān)內(nèi)容在行業(yè)資料-天天文庫。
1、摘要:正文:大綱:1.引言;隨著網(wǎng)絡(luò)安全技術(shù)的飛速發(fā)展,緩沖區(qū)溢出漏洞已經(jīng)成為當前最具安全威脅的漏洞之一,緩沖區(qū)溢出攻擊也成為一種非常有效而常見的攻擊方法。如Internet上的第1例蠕蟲(Morris)攻擊,就是利用了fingerd的緩沖區(qū)溢出漏洞。SANS評選出的2005年威脅最大的20個漏洞中,有8個跟緩沖區(qū)溢出有關(guān)。根據(jù)CNCERT最近幾周的計算機安全漏洞的統(tǒng)計數(shù)據(jù),與緩沖區(qū)溢出有關(guān)的安全事件占了很大的比例。這些都充分說明了研究緩沖區(qū)溢出的重要性。本文主要介紹了windows下的緩沖區(qū)溢出的相關(guān)知識。2.漏洞原因和原理;2.1產(chǎn)生原因;當向一個已分配了確定存
2、儲空間的緩沖區(qū)內(nèi)復(fù)制多于該緩沖區(qū)處理能力的數(shù)據(jù)時,就會發(fā)生緩沖區(qū)溢出,溢出包括堆溢出和堆棧溢出。它與程序在內(nèi)存中的分布有關(guān),而它產(chǎn)生的直接原因是由于C/C++程序中的一些函數(shù)調(diào)用時,沒有進行邊界檢查,如C函數(shù)庫中的strcpy(),strcat(),sprintf(),gets()等都是不安全的。由上面的分析可知要產(chǎn)生緩沖區(qū)溢出,需要有幾個條件:1)程序編譯時在堆棧上分配了固定大小的緩沖區(qū),并且在對緩沖區(qū)進行訪問時沒有提供邊界檢查。這條在C/C++語言中就滿足,而對于有邊界檢查的語言,如Pascal等,就沒有這樣的溢出問題。2)程序調(diào)用了沒有進行邊界檢查的函數(shù)來訪問
3、(寫操作)緩沖區(qū),這些函數(shù)沒有對訪問的緩沖區(qū)的大小進行判斷。由于在C語言中,字符串以0字節(jié)來標識結(jié)尾,其中沒有字符串的長度信息,所以幾個沒有判斷字符串長度的字符串拷貝函數(shù)就是容易出現(xiàn)問題的函數(shù)。這些函數(shù)有:strcat()、strcpy()、sprintf()等。3)即使程序使用了上面所說的問題函數(shù)也不一定會出現(xiàn)溢出漏洞,漏洞發(fā)生的最后一個條件是程序員由于粗心,未檢查用戶輸入數(shù)據(jù)的長度就將其直接復(fù)制到緩沖區(qū)中去。雖然這看起來是一件小事,很容易杜絕??上У氖钦驗橛写罅看中牡某绦騿T的存在,使得溢出漏洞變得非常的普遍。2.2原理;圖1堆棧緩沖區(qū)示意圖程序的堆棧是先進后出
4、的一種數(shù)據(jù)結(jié)構(gòu),堆棧的生長方向適合內(nèi)存相反的(如圖1)。當調(diào)用一個函數(shù)時,首先是函數(shù)的參數(shù)逆序進棧,然后將eip里面的內(nèi)容進棧作為函數(shù)的返回地址(ret),即函數(shù)調(diào)用結(jié)束后程序跳轉(zhuǎn)的地址,接著保存現(xiàn)在程序的棧基指針(ebp),并將當前棧頂指針(esp)拷入ebp作為新的基地址.最后將esp減去一定數(shù)值用來為本地變量留出一定空間。緩存區(qū)往往就分配在這段空間中。由于堆棧是由內(nèi)存高地址向內(nèi)存低地址方向增長,而數(shù)組的變量是從內(nèi)存低地址向高地址方向增長,這時如果沒有對數(shù)組的越界進行檢查和限制,通過向程序的數(shù)組緩沖區(qū)寫入超出其長度的內(nèi)容,覆蓋堆棧原來的返回地址(ret),就會造
5、成緩沖區(qū)溢出,從而破壞程序的堆棧。如果構(gòu)造特殊的注入向量覆蓋ret值使程序轉(zhuǎn)而執(zhí)行惡意代碼(shellcode),就達到攻擊的目的。1.基于緩沖區(qū)漏洞的攻擊過程;由上所述可知,堆棧緩沖區(qū)溢出漏洞的攻擊利用的3個步驟是:1)溢出點ret的定位;定位ret的流程是用一定格式的字符串覆蓋存在溢出漏洞的緩沖區(qū),使程序溢出,然后根據(jù)溢出結(jié)果計算ret的位置。最常用的方法是利用報錯對話框精確計算出溢出返回點的方法,如圖2中的報錯對話框所示,可以看到是“0x79797979”覆蓋到了溢出點。依次類推,我們可以不斷給一個數(shù)組反復(fù)賦值,利用整除和求余等數(shù)學方法來精確計算溢出點的位置。
6、圖2溢出報錯對話框2)構(gòu)造shellcode;確定下來溢出點位置后,就需要有可以執(zhí)行的shellcode來達到入侵的目的。shellcode的編寫主要有兩種lodsd方法,一是用C等高級語言編寫經(jīng)反匯編后提取二進制碼。二是直接使用匯編語言編寫并提取二進制碼。使用c語言編寫生成的代碼較長,但編寫調(diào)試簡單,且可以根據(jù)不同的需要靈活更改代碼。而利用匯編語言生成的代碼更為簡練,但調(diào)試復(fù)雜,一旦編寫成功后不易修改。3)用特定地址覆蓋ret并且使其跳轉(zhuǎn)到shellcode,并執(zhí)行。是將返回點覆蓋成jmpesp或callebx的地址。為了通用性使用kernel32.dll中的指令
7、地址.因為同一系統(tǒng)中該模塊裝載地址變化可能小。覆蓋方法主要有兩種:①NNNNNNNNNSSSSSSSSSSSRRRRRRRRRRRRRR型。適合于大緩沖區(qū),“N”代表空指令(NOP),也就是0x90,在實際運行中,程序?qū)⑹裁匆膊蛔觯且恢毖又@些NOPS運行下去,直到遇到不是NOPS的指令再執(zhí)行之;“S”代表ShellCode;“R”代表覆蓋的返回地址,思路是把返回地址R覆蓋為nops的大概位置,這樣就會跳到Nop中,然后繼續(xù)執(zhí)行,直到我們的ShellCode中。但這種方法由于定位不準確,所以使用起來也不準確。②RRRRRRRRRRNNNNNNNNNNNSSS