緩衝區溢位原理
目的
指的是利用程式的漏洞,向緩衝衝區寫入使溢位的值,可用來達到以下目的:
- 程序破壞
- 控制程式流程
- 取得系統的控制權
以下將透過編寫簡單的程式,並輸入過長字串讓程序當掉,以了解緩衝區溢位的原理。
環境介紹
- OS:Windows XP_x86 (SP3)
- IDE:VC++ 6.0
事前準備及利用緩衝區漏洞
這裡以C寫一段存在緩衝區漏洞的程式
1 |
|
這段程式是先宣告name變數資料型態為Char的陣列,並設值為”HAO-WEI”,
並在主程式中,宣告buffer變數一樣為Char的陣列的資料型態,設定與name變數相同長度,因為HAO-WEI後面還有一個’\0′
使用strcpy函數將name的字串複製給buffer,最後再輸出。
以上是有存在緩衝區溢位的程式碼,這邊思考一下,如果name的長度比8更長,或是buffer長度比8小,讓他真的發生緩衝區溢位,那麼會發生什麼事呢?
這邊將name內容設為HAO-WEIHAO-WEI,長度為15,並編譯執行
1 |
|
程序雖然成功的輸出HAO-WEIHAO-WEI,但隨即就當掉了。
緩衝區不就只是滿了,為什麼會發生這樣的事情呢?
分析說明
要解釋這個問題時,先講解程式在執行時Stack運作原理
程式在直行時會有一塊記憶體是存放Stack的部分
當進入副程式時,系統會給予這副程式一塊可用記憶體,稱為Stack Frame(如下圖)
其中epb跟esp都是暫存器的值
- epb表示Stack底端
- esp表示Stack頂端
每一個Stack Frame都有屬於自己的esp跟ebp
所以只要把epb的值+4就可以拿到這個Function的變數2的值
epb的值+8也就可以拿到變數1的值
而最上面綠色那塊則是這Function可用的其他記憶體空間
另外也會把這個Function完成後
等等要執行下一個指令的位置寫到Return Address這裡
也會把呼叫這個Function的舊ebp保存起來
以供結束此Function能夠回復上一個Function的ebp
這樣Function一直不斷呼叫,記憶體不斷的往上疊,也不會亂掉,因為每個Function只需在意他自己的ebp跟esp
這邊用OllyDbg來進行動態分析,以了解程式的組合語言以及執行時的Stack變化
進入FUNCTION前
我們先把程式停在進入Main()這個Function前
另外也需特別注意下一個指令的位置00401699
結束完Main()時會繼續往這裡走,所以需要把這個位置寫到Stack中(等等下面圖片會看到)
1 | 00401694 CALL BufferOv.00401005 // 表示CALL Main() |
以及他的Stack狀況
可以知道目前esp為0012FF88
進入FUNCTION後
觀察一下Stack狀態
就可以發現目前的esp變為0012FF24
而ebp為0012FF80 其值為0012FFC0(上一個Function的ebp)
而0012FF84(ebp + 4) 其值為00401699(為Main()執行完要回去的位置,也稱Return Address)
而這個Main()所用記憶體也就是0012FF24 ~ 0012FF7C這些空間
執行STRCPY前
我們來看一下Main()裡面寫到的strcpy這Function的C語言以及其對應組合語言的部分
1 | strcpy(buffer, name); |
strcpy的API
1 | char * strcpy ( char * destination, const char * source ); |
可以知道他把”HAO-WEI”這些字串拷貝到[ebp – 8]也就是0012FF78這個位置上
執行STRCPY後
我們來看看0012FF78這個位置的值發生什麼變化
已經被填入”HAO-WEI”的字串了,看起來沒什麼問題
那如果是填入過長字串如”HAO-WEIHAO-WEI”會怎樣呢?我們來看看
結果發現0012FF84原本放Main()執行完要去的位置被覆寫掉了,變成00004945
意謂著等等結束Main()會跳到00004945位置繼續執行指令,而這個位置如果是空的,程式自然就會當掉,發生以下情形
很明顯的圖片上出現的0x00004945就是這個意思
最後
換個角度想,如果覆寫掉的這個位置是存在的,就樣是不是就能控制程式流程,隨心所欲的跳到想要的位置呢?