【安全健行】(2):Linux漏洞基礎

2015/5/12 18:36:42

時隔這麼久,自己終於重新開始了安全之路,雖然每天的工作和研讀的論文也都是安全領域的技術,但是自己心裏真正的安全還是漏洞的研究。因此,自己決定業餘來自學這部分,今天算是一個正式的開始吧!

今天來簡單介紹下Linux漏洞,因爲Linux給予了用戶更大的自由度和操控性,因此更加適合進行安全研究,我們也從Linux開始。這部分主要分爲以下小節:

  • 棧的操作

  • 緩衝區溢出的基本原理

  • 本地緩衝區溢出漏洞***框架

  • 小緩衝區的漏洞***框架

一、棧的操作

是操作系統進程內存中特有的結構,當系統運行一個程序,程序執行所需要的信息、數據都會以進程的形式存放到內存中供隨時讀寫,這時內存中程序代碼的大致結構就像下面這個樣子:

7LoRUJE.png

棧是一種特殊的數據結構,可以想象出餐館疊在一起的盤子,每次放上一個新盤子,之前最上面的盤子就到了下面,新盤子成爲了最頂上的盤子;而取盤子時,總是從上向下依次取出,這樣的數據結構我們稱之爲先進後出(FILO),棧就是一種這樣的結構。

棧的增長順序,在任何一個系統中都是由高內存向低內存擴展,我能想到一個直觀的理由是系統默認可以從低內存開始處理數據(不考慮大端存儲的話)。

棧有兩個基本的操作,一個是將數據/元素壓入棧中,即PUSH操作;另一個則相反,是將棧頂的元素彈出,存儲到寄存器中,即POP操作。

內存中每個進程在內存棧段中都有自己的棧,而且棧始終是由最高內存地址向最低內存地址反向增長的。關於棧有兩個重要的寄存器,一個是擴展基地址指針EBP,它指向棧底,即較高地址;另一個是擴展棧頂指針ESP,指向棧的較低地址。

系統在實際運行程序時,棧的應用往往表現在函數調用。每個函數都會有自己的棧,因此當發生一次函數調用時,調用函數和被調用函數都要進行一些棧的“交接”。比如對於調用函數來說,需要做以下工作:

  1. 調用程序首先將被調用函數的參數按照逆序壓入棧中,從而對函數調用進行設置;

  2. 將當前的EIP指針(擴展指令指針,只向CPU下一步要處理的指令)保存到棧上,這樣在被調用函數返回時就可以在離開的地方繼續執行,這個地址被稱作返回地址

  3. 執行call命令,將被調用函數的地址放入EIP中執行;

這樣,調用函數將當前的運行狀態完整保存到棧中,同時壓入了被調用函數的參數,接下來,就是被調用函數的工作了,我們一般稱之爲“開場白”

  1. “開場白”:保存當前EBP到棧中,然後將ESP設置爲EBP,然後ESP減小,留出存放變量的空間;

  2. “收場白”:其實要簡單些,這裏主要是將ESP增加到EBP,釋放清空棧,然後彈出EIP,繼續之前中斷的執行,一般就是利用leave和ret兩個指令完成。

我在自己的虛擬機Ubuntu12.04上編寫了一個簡單的C程序,然後使用disassemble命令反彙編程序文件,可以看到清晰的“開場白”和“收場白”

hgXWDlI.png

二、緩衝區溢出

緩衝區,本身是系統用於臨時存放數據的一塊內存區域,我們經常會用到變量複製的操作,將一個緩衝區的數據複製到另一個緩衝區,但是遺憾地是並非所有的函數都執行了嚴格的緩衝區大小檢查操作。因此,當向一個緩衝區中複製超過其大小的數據時,數據就會超出其邊界,覆蓋影響到其相鄰的區域。

假設我們現在有一個具有兩個參數的函數調用過程,我們通過此時緩衝區在內存中的結構來說明下緩衝區溢出的原理。

WiOlZme.png

在被調用函數得到執行權之前,調用函數會講被調用函數的參數逆序壓進棧中,這裏就是Temp1和Temp2,然後壓棧保存當前的EIP指針,最後利用Call命令將被調用函數的地址設置爲EIP開始執行。

被調用函數的棧從EBP開始,到ESP爲止,中間可以是函數內部定義的局部變量。如果函數內部定義了一個變量name是一個10字節的數組,當將一個100字節的Temp2複製到name時無疑會出現數據的越界,比如覆蓋到EBP,甚至到達EIP,而此時原先的EIP便遭到了破壞,造成了緩衝區溢出。

緩衝區溢出的結果一般會造成拒絕服務,但是這是一個相對比較好的結果,因爲起碼程序給出了提示,有些時候EIP會被***者控制並以用戶級訪問權限執行惡意代碼。而第三種則是最糟糕的情況,也就是EIP被控制並在系統級或根級執行惡意代碼,此時***者獲得了系統最高權限。

三、本地緩衝區溢出漏洞***

本地緩衝區溢出漏洞***要比遠程漏洞***容易些,因爲能夠訪問系統內存空間,並且更容易調試***代碼。

一般一個漏洞***程序由三個部分構成:

  1. NOP雪橇:彙編代碼中有一個空指令NOP,意味着不執行任何操作,而只是移動到嚇一跳命令。緩衝區溢出***的思路是通過緩衝區溢出覆蓋控制EIP,使得EIP跳轉到我們的***代碼,而有時控制計算的並非十分精確,現實中也存在多種情況,因此我們需要添加一段NOP指令作爲返回地址的“緩衝”,以防EIP超出***代碼的範圍。

  2. Shellcode:上面所說EIP需要指向一個***代碼,這個代碼就是我們的Shellcode了。原本Shellcode的作用僅僅是返回一個執行shell,也是因此得名,但是現在的Shellcode可以執行更爲複雜的***。Shellcode是執行***命令的機器代碼,因此實質上是二進制碼,通常以十六進制表示。

  3. 重複返回地址:確定好NOP雪橇和Shellcode的地址後,就需要確定EIP指向的地址,並且進行一定程度的重複,作爲緩衝區溢出的填充,一定要覆蓋到EIP,作爲EIP指向Shellcode纔可以實施***。

最後,我們將以上三個部分組合起來,就是一個緩衝區溢出***的框架:

3gMv0Gs.png

四、小緩衝區的溢出漏洞***

一般Shellcode不會太大,但是也不會太小,如果我們發現存在漏洞的緩衝區很小,不足以存放上面的Shellcode,那該如何呢?

方法就是將Shellcode存放到環境變量的位置,然後緩衝區覆蓋EIP指向Shellcode。

這樣之所以可以成功,是因爲所有Linux ELF文件在映射到內存中時會將最後的相對地址設爲0xbfffffff。環境變量和參數存儲在這個區域,這些數據的下面就是函數棧,結構如圖:

W1ZlmWb.png

這樣,我們就可以繼續將EIP指向Shellcode執行***。

PS

好了,Linux漏洞的基礎知識就介紹到這裏了,一些內存、堆棧的知識可以參考我之前的文章。今天雖然講漏洞,但是沒有列出代碼和實驗演示,感興趣地朋友可以去Metasploit的網站瀏覽更多信息,那裏有許多***實驗的分享。

ReferGray Hat Hacking: The Ethical Hacker's Handbook, Third Edition


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章