這篇文章將為大家詳細(xì)講解有關(guān)如何進(jìn)行棧溢出漏洞原理分析與利用,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
在曲江等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需規(guī)劃網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計(jì),成都全網(wǎng)營(yíng)銷,外貿(mào)網(wǎng)站制作,曲江網(wǎng)站建設(shè)費(fèi)用合理。
和我一樣,有一些計(jì)算機(jī)專業(yè)的同學(xué)可能一直都在不停地碼代碼,卻很少關(guān)注程序是怎么執(zhí)行的,也不會(huì)考慮到自己寫(xiě)的代碼是否會(huì)存在棧溢出漏洞,借此機(jī)會(huì)我們一起走進(jìn)棧溢出。
在了解棧溢出之前我們先了解一下程序執(zhí)行過(guò)程
程序的執(zhí)行過(guò)程可看作連續(xù)的函數(shù)調(diào)用。當(dāng)一個(gè)函數(shù)執(zhí)行完畢時(shí),程序要回到call指令的下一條指令繼續(xù)執(zhí)行,函數(shù)調(diào)用過(guò)程通常使用堆棧實(shí)現(xiàn)
#include
#include
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位可執(zhí)行文件,放在ollydbg中就行調(diào)試,來(lái)詳細(xì)看一下執(zhí)行過(guò)程
因?yàn)槌绦虻膱?zhí)行可以看做一個(gè)一個(gè)函數(shù)的執(zhí)行(main函數(shù)也一樣),因此我們挑選其中一個(gè)即可,在test1()函數(shù)設(shè)置斷點(diǎn)
F7單步調(diào)試第一步mov dword ptr ss:[esp],0×1,進(jìn)行傳參,簡(jiǎn)潔明了。
第二步call mian.00401559,進(jìn)入test(),這里我們關(guān)注一下esp和棧頂值,將該指令的下一條指令的地址進(jìn)行壓棧,既然有壓棧那么就會(huì)有出棧,這就與函數(shù)中的retn指令形成呼應(yīng)。
第三步push ebp,就是把ebp的值進(jìn)行壓棧,那么這個(gè)ebp是什么呢?有什么用呢?
EBP叫做擴(kuò)展基址指針寄存器(extended base pointer) ,里面放一個(gè)指針,該指針指向系統(tǒng)棧最上面一個(gè)棧幀的底部,用于C運(yùn)行庫(kù)訪問(wèn)棧中的局部變量和參數(shù)。那么這一步的意義就是:保存舊棧幀中的幀基指針以便函數(shù)返回時(shí)恢復(fù)舊棧幀
第四步,mov ebp,esp,將esp的值放在ebp中,我們?cè)賮?lái)了解一下什么是esp?
ESP(Extended Stack Pointer)為擴(kuò)展棧指針寄存器,是指針寄存器的一種,用于存放函數(shù)棧頂指針,指向棧的棧頂(下一個(gè)壓入棧的活動(dòng)記錄的頂部),也就是它不停在變,剛才提到的ebp指向棧底,在函數(shù)內(nèi)部執(zhí)行過(guò)程中是不變。
那么我們?cè)倏匆幌逻@一步的作用:
從第三步可以知道esp存儲(chǔ)的值是舊棧幀中的幀基指針,而esp值棧頂指針,隨時(shí)都在變,因此為了函數(shù)結(jié)束后能恢復(fù),把esp值(外層函數(shù)棧底地址)保存在本函數(shù)棧底ebp中。簡(jiǎn)而言之,將內(nèi)部函數(shù)ebp的值作為地址,它存放外函數(shù)的ebp的值。這一步在末尾也存在逆向指令leave。
第五步是sub esp,0×28,開(kāi)辟該函數(shù)的局部變量空間
緊接著第六步mov dword ptr ss:[ebp-0xC],0×6,給變量a一個(gè)大小是0xC的空間,并且賦值。
然后就是傳參字符1的ascii碼,調(diào)用printf函數(shù),把返回值放到eax。
我們重點(diǎn)來(lái)看leave指令,可以發(fā)現(xiàn)ebp的值恢復(fù)了,esp的值也變了,相當(dāng)于mov esp,ebp;pop ebp
最后執(zhí)行retn指令,至此一個(gè)函數(shù)執(zhí)行完畢,esp和eip的值都被改變,相當(dāng)于pop eip,然后程序繼續(xù)執(zhí)行。EIP是指令寄存器,存放當(dāng)前指令的下一條指令的地址。CPU該執(zhí)行哪條指令就是通過(guò)EIP來(lái)指示的
分析完這一過(guò)程,相信大家對(duì)函數(shù)是怎么執(zhí)行的應(yīng)該明朗了,那么我們言歸正傳,繼續(xù)聊一下棧溢出。首先我們先看一下什么是棧?
棧可以看作是一個(gè)漏斗,棧底地址大,棧頂?shù)刂沸。缓笤谝粋€(gè)存儲(chǔ)單元中,按照由小到大進(jìn)行存儲(chǔ),它的目的是賦予程序一個(gè)方便的途徑來(lái)訪問(wèn)特定函數(shù)的局部數(shù)據(jù),并從函數(shù)調(diào)用者那邊傳遞信息。
棧溢出屬于緩沖區(qū)溢出,指的是程序向棧中某個(gè)變量中寫(xiě)入的字節(jié)數(shù)超過(guò)了這個(gè)變量本身所申請(qǐng)的字節(jié)數(shù),因而導(dǎo)致與其相鄰的棧中的變量的值被改變。
另外,我們也不難發(fā)現(xiàn),發(fā)生棧溢出的基本前提是:程序必須向棧上寫(xiě)入數(shù)據(jù)、寫(xiě)入的數(shù)據(jù)大小沒(méi)有被良好地控制。引用一個(gè)例子來(lái)了解一下棧溢出
#include
#include
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;
}
很顯然符合以上兩個(gè)條件,gets()成為突破口我們?cè)谥骱瘮?shù)處下斷點(diǎn),運(yùn)行和調(diào)試
lea eax,dword ptr ss:[ebp-0x14] 這時(shí)開(kāi)辟一個(gè)空間給變量,也即是s,如圖所示
我們想執(zhí)行sucess()函數(shù),要怎么辦呢?
執(zhí)行完vulnerable()函數(shù)后,會(huì)還原ebp,改變esp的值(leave),然后retn,也就是pop eip,然后CPU根據(jù)eip指針指向的指令繼續(xù)運(yùn)行。
我們能抓到的點(diǎn)就是控制eip,怎么控制?通過(guò)控制棧頂?shù)闹担敲礂m數(shù)闹凳鞘裁??棧頂?shù)闹凳沁M(jìn)入該函數(shù)時(shí)儲(chǔ)存的下一條指令的地址。這里提一點(diǎn),進(jìn)入函數(shù),要保存兩個(gè)值:下一條命令的地址、EBP舊棧幀的幀基指針,只有這樣才能完全恢復(fù)。
此時(shí)我們可以構(gòu)造payload,來(lái)控制我們要控制的地方,棧中存儲(chǔ)EBP值的存儲(chǔ)單元的上一個(gè)存儲(chǔ)單元,也就是圖中的存儲(chǔ)address的存儲(chǔ)單元
我們先試驗(yàn)一下輸入0×14 *’A'+BBBB+0000,發(fā)生的變化
很好,按照我們的預(yù)想進(jìn)行(python -c ‘print “A”* 0×18+p32(0×00401520)’) 就可以達(dá)到棧溢出的效果
關(guān)于如何進(jìn)行棧溢出漏洞原理分析與利用就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。