您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關如何進行棧溢出漏洞原理分析與利用,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
和我一樣,有一些計算機專業的同學可能一直都在不停地碼代碼,卻很少關注程序是怎么執行的,也不會考慮到自己寫的代碼是否會存在棧溢出漏洞,借此機會我們一起走進棧溢出。
在了解棧溢出之前我們先了解一下程序執行過程
程序的執行過程可看作連續的函數調用。當一個函數執行完畢時,程序要回到call指令的下一條指令繼續執行,函數調用過程通常使用堆棧實現
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
test1(1);
test2(2);
test3(3);
return 0;
}
int test1(int test1){
int a = 6;
printf(“1″);
return 1;
}
int test2(int test2){
printf(“2″);
return 2;
}
int test3(int test3){
printf(“3″);
return 3;
}
編譯成32位可執行文件,放在ollydbg中就行調試,來詳細看一下執行過程
因為程序的執行可以看做一個一個函數的執行(main函數也一樣),因此我們挑選其中一個即可,在test1()函數設置斷點
F7單步調試第一步mov dword ptr ss:[esp],0×1,進行傳參,簡潔明了。
第二步call mian.00401559,進入test(),這里我們關注一下esp和棧頂值,將該指令的下一條指令的地址進行壓棧,既然有壓棧那么就會有出棧,這就與函數中的retn指令形成呼應。
第三步push ebp,就是把ebp的值進行壓棧,那么這個ebp是什么呢?有什么用呢?
EBP叫做擴展基址指針寄存器(extended base pointer) ,里面放一個指針,該指針指向系統棧最上面一個棧幀的底部,用于C運行庫訪問棧中的局部變量和參數。那么這一步的意義就是:保存舊棧幀中的幀基指針以便函數返回時恢復舊棧幀
第四步,mov ebp,esp,將esp的值放在ebp中,我們再來了解一下什么是esp?
ESP(Extended Stack Pointer)為擴展棧指針寄存器,是指針寄存器的一種,用于存放函數棧頂指針,指向棧的棧頂(下一個壓入棧的活動記錄的頂部),也就是它不停在變,剛才提到的ebp指向棧底,在函數內部執行過程中是不變。
那么我們再看一下這一步的作用:
從第三步可以知道esp存儲的值是舊棧幀中的幀基指針,而esp值棧頂指針,隨時都在變,因此為了函數結束后能恢復,把esp值(外層函數棧底地址)保存在本函數棧底ebp中。簡而言之,將內部函數ebp的值作為地址,它存放外函數的ebp的值。這一步在末尾也存在逆向指令leave。
第五步是sub esp,0×28,開辟該函數的局部變量空間
緊接著第六步mov dword ptr ss:[ebp-0xC],0×6,給變量a一個大小是0xC的空間,并且賦值。
然后就是傳參字符1的ascii碼,調用printf函數,把返回值放到eax。
我們重點來看leave指令,可以發現ebp的值恢復了,esp的值也變了,相當于mov esp,ebp;pop ebp
最后執行retn指令,至此一個函數執行完畢,esp和eip的值都被改變,相當于pop eip,然后程序繼續執行。EIP是指令寄存器,存放當前指令的下一條指令的地址。CPU該執行哪條指令就是通過EIP來指示的
分析完這一過程,相信大家對函數是怎么執行的應該明朗了,那么我們言歸正傳,繼續聊一下棧溢出。首先我們先看一下什么是棧?
棧可以看作是一個漏斗,棧底地址大,棧頂地址小,然后在一個存儲單元中,按照由小到大進行存儲,它的目的是賦予程序一個方便的途徑來訪問特定函數的局部數據,并從函數調用者那邊傳遞信息。
棧溢出屬于緩沖區溢出,指的是程序向棧中某個變量中寫入的字節數超過了這個變量本身所申請的字節數,因而導致與其相鄰的棧中的變量的值被改變。
另外,我們也不難發現,發生棧溢出的基本前提是:程序必須向棧上寫入數據、寫入的數據大小沒有被良好地控制。引用一個例子來了解一下棧溢出
#include <stdio.h>
#include <string.h>
void success() { puts(“You Hava already controlled it.”); }
void vulnerable() {
char s[12];
gets(s);
puts(s);
return;
}
int main(int argc, char **argv) {
vulnerable();
return 0;
}
很顯然符合以上兩個條件,gets()成為突破口我們在主函數處下斷點,運行和調試
lea eax,dword ptr ss:[ebp-0x14] 這時開辟一個空間給變量,也即是s,如圖所示
我們想執行sucess()函數,要怎么辦呢?
執行完vulnerable()函數后,會還原ebp,改變esp的值(leave),然后retn,也就是pop eip,然后CPU根據eip指針指向的指令繼續運行。
我們能抓到的點就是控制eip,怎么控制?通過控制棧頂的值,那么棧頂的值是什么?棧頂的值是進入該函數時儲存的下一條指令的地址。這里提一點,進入函數,要保存兩個值:下一條命令的地址、EBP舊棧幀的幀基指針,只有這樣才能完全恢復。
此時我們可以構造payload,來控制我們要控制的地方,棧中存儲EBP值的存儲單元的上一個存儲單元,也就是圖中的存儲address的存儲單元
我們先試驗一下輸入0×14 *’A'+BBBB+0000,發生的變化
很好,按照我們的預想進行(python -c ‘print “A”* 0×18+p32(0×00401520)’) 就可以達到棧溢出的效果
關于如何進行棧溢出漏洞原理分析與利用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。