古詩詞大全網 - 成語用法 - .緩沖區溢出會產生什麽危害?

.緩沖區溢出會產生什麽危害?

在當前網絡與分布式系統安全中,被廣泛利用的50%以上都是緩沖區溢出,其中最著名的例子是1988年利用fingerd漏洞的蠕蟲。而緩沖區溢出中,最為危險的是堆棧溢出,因為入侵者可以利用堆棧溢出,在函數返回時改變返回程序的地址,讓其跳轉到任意地址,帶來的危害壹種是程序崩潰導致拒絕服務,另外壹種就是跳轉並且執行壹段惡意代碼,比如得到shell,然後為所欲為。

首先,介紹壹下,與堆棧有關的壹些概念:動態內存有兩種,堆棧(stack),堆(heap)。堆棧在內存上端,堆在內存下端,當程序執行時,堆棧向下朝堆增長,堆向上朝堆棧增長。通常,局部變量,返回地址,函數的參數,是放在堆棧裏面的。

低地址

局部變量

舊的基指針

返回地址

函數的參數(左)

函數的參數(。。。)

函數的參數(右)

高地址

我們可以寫壹個小程序測試:

#include "string.h"

void test(char *a);

int main(int argc, char* argv[])

{

char a[] = “hello”;

test(a);

return 0;

}

void test(char *a)

{

char* j;

char buf[6];

strcpy(buf,a);

printf("&main=%p\n",&main);

printf("&buf=%p\n",&buf);

printf("&a=%p\n",&a);

printf("&test=%p\n",&test);

for ( j=buf-8;j<((char *)&a)+8;j++)

printf("%p: 0x%x\n",j, *(unsigned char *)j);

}

Main定義壹個字符串hello,然後調用test函數,在test函數中,有壹個長度為6的局部字符串變量buf,然後把復制參數a復制到buf中,這裏因為沒有a的長度小於等於buf的長度,所以並沒有溢出buf。然後顯示各個函數,參數,局部變量的地址,以及局部字符串變量buf和參數a之間的地址,我們看到:

&main=0040100A

&buf=0012FF14

&a=0012FF28

&test=00401005

0012FF0C: 0xcc

0012FF0D: 0xcc

0012FF0E: 0xcc

0012FF0F: 0xcc

0012FF10: 0xcc

0012FF11: 0xcc

0012FF12: 0xcc

0012FF13: 0xcc

0012FF14: 0x68 h 這裏就是buf了!

0012FF15: 0x65 e

0012FF16: 0x6c l

0012FF17: 0x6c l

0012FF18: 0x6f o

0012FF19: 0x0 \0

0012FF1A: 0xcc

0012FF1B: 0xcc

0012FF1C: 0x1c 這裏是

0012FF1D: 0xff 兩個

0012FF1E: 0x12 舊的

0012FF1F: 0x0 基指針,不管他

0012FF20: 0x80

0012FF21: 0xff

0012FF22: 0x12

0012FF23: 0x0

0012FF24: 0x34 這個就是

0012FF25: 0xb8 返回地址了

0012FF26: 0x40 和main的地址很

0012FF27: 0x0 接近吧!

0012FF28: 0x78 這個是

0012FF29: 0xff 參數a,即

0012FF2A: 0x12 a字符串的

0012FF2B: 0x0 地址

0012FF2C: 0xe

0012FF2D: 0x0

0012FF2E: 0x0

0012FF2F: 0x0

由於c編譯器不會自己做邊界檢查的,所以,如果buf中的內容足夠長,而不是hello,那麽很有可能覆蓋掉原來的返回地址,那麽程序就會跳轉到其他地方,為了試驗,我們定義壹個簡單的函數echo,讓test返回的時候跳轉到echo。

用printf("&echo=%p\n",&echo); 我已經知道了echo的地址是0x0040100f,從上面的例子已經知道從0012ff14到0012ff27要覆蓋多少數據,數壹下就知道了?8?1 改寫如下:

#include "string.h"

void test(char *a);

void echo();

int main(int argc, char* argv[])

{

char a[16];

int i;

for(i=0;i<16;i++) a='x'; //覆蓋不重要的部分,為了達到返回地址

a[16]=0xf; //在這裏改寫了返回地址

a[17]=0x10;

a[18]=0x40;

a[19]=0x00; //壹方面高字節正好是00,同時00又是字符串的結尾

test(a);

return 0;

}

void test(char *a)

{

char* j;

char buf[6];

strcpy(buf,a); //分配的緩沖區只有5,結果卻有19,溢出了!

printf("&main=%p\n",&main);

printf("&buf=%p\n",&buf);

printf("&a=%p\n",&a);

printf("&echo=%p\n",&echo);

printf("&test=%p\n",&test);

for ( j=buf-8;j<((char *)&a)+8;j++)

printf("%p: 0x%x\n",j, *(unsigned char *)j);

}

void echo()

{

printf("haha!\n");

printf("haha!\n");

printf("haha!\n");

printf("haha!\n");

}

結果,我們看到地址顯示完以後,出現了echo函數裏面的haha!\nhaha!\nhaha!\nhaha!\n,說明溢出跳轉成功,但是,在結束的時候出現了程序崩潰,這是因為echo找不到它的返回地址導致的。但是今天我們的目的,利用溢出執行其他代碼的任務已經實現了,我在下壹次會告訴大家如何把堆棧溢出和shell code結合起來。謝謝大家,by the way,我也是初學者,有理解偏差的地方,希望高手指教,