c語言有漏洞的接口函數(shù),C語言漏洞

什么是C語言緩沖區(qū)溢出漏洞?怎么利用?誰可以提供詳細的資料

緩沖區(qū)溢出漏洞入門介紹

豐鎮(zhèn)網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)!從網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、APP開發(fā)、響應式網(wǎng)站建設等網(wǎng)站項目制作,到程序開發(fā),運營維護。成都創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設就選成都創(chuàng)新互聯(lián)。

文/hokersome

一、引言

不管你是否相信,幾十年來,緩沖區(qū)溢出一直引起許多嚴重的安全性問題。甚至毫不夸張的說,當前網(wǎng)絡種種安全問題至少有50%源自緩沖區(qū)溢出的問題。遠的不說,一個沖擊波病毒已經(jīng)令人談溢出色變了。而作為一名黑客,了解緩沖區(qū)溢出漏洞則是一門必修課。網(wǎng)上關于溢出的漏洞的文章有很多,但是大多太深或者集中在一個主題,不適合初學者做一般性了解。為此,我寫了這篇文章,主要是針對初學者,對緩沖區(qū)溢出漏洞進行一般性的介紹。

緩沖區(qū)溢出漏洞是之所以這么多,是在于它的產(chǎn)生是如此的簡單。只要C/C++程序員稍微放松警惕,他的代碼里面可能就出現(xiàn)了一個緩沖區(qū)溢出漏洞,甚至即使經(jīng)過仔細檢查的代碼,也會存在緩沖區(qū)溢出漏洞。

二、溢出

聽我說了這些廢話,你一定很想知道究竟什么緩沖區(qū)溢出漏洞,溢出究竟是怎么發(fā)生的。好,現(xiàn)在我們來先弄清楚什么是溢出。以下的我將假設你對C語言編程有一點了解,一點點就夠了,當然,越多越好。

盡管緩沖區(qū)溢出也會發(fā)生在非C/C++語言上,但考慮到各種語言的運用程度,我們可以在某種程度上說,緩沖區(qū)溢出是C/C++的專利。相信我,如果你在一個用VB寫的程序里面找溢出漏洞,你將會很出名?;氐秸fC/C++,在這兩種使用非常廣泛的語言里面,并沒有邊界來檢查數(shù)組和指針的引用,這樣做的目的是為了提高效率,而不幸的是,這也留下了嚴重的安全問題。先看下面一段簡單的代碼:

#includestdio.h

void main()

{

char buf[8];

gets(buf);

}

程序運行的時候,如果你輸入“Hello”,或者“Kitty”,那么一切正常,但是如果輸入“Today is a good day”,那么我得通知你,程序發(fā)生溢出了。很顯然,buf這個數(shù)組只申請到8個字節(jié)的內(nèi)存空間,而輸入的字符卻超過了這個數(shù)目,于是,多余的字符將會占領程序中不屬于自己的內(nèi)存。因為C/C++語言并不檢查邊界,于是,程序?qū)⒖此普@^續(xù)運行。如果被溢出部分占領的內(nèi)存并不重要,或者是一塊沒有使用的內(nèi)存,那么,程序?qū)^續(xù)看似正常的運行到結(jié)束。但是,如果溢出部分占領的正好的是存放了程序重要數(shù)據(jù)的內(nèi)存,那么一切將會不堪設想。

實際上,緩沖區(qū)溢出通常有兩種,堆溢出和堆棧溢出。盡管兩者實質(zhì)都是一樣,但由于利用的方式不同,我將在下面分開介紹。不過在介紹之前,還是來做一些必要的知識預備。

三、知識預備

要理解大多數(shù)緩沖區(qū)溢出的本質(zhì),首先需要理解當程序運行時機器中的內(nèi)存是如何分配的。在許多系統(tǒng)上,每個進程都有其自己的虛擬地址空間,它們以某種方式映射到實際內(nèi)存。我們不必關心描述用來將虛擬地址空間映射成基本體系結(jié)構(gòu)的確切機制,而只關心理論上允許尋址大塊連續(xù)內(nèi)存的進程。

程序運行時,其內(nèi)存里面一般都包含這些部分:1)程序參數(shù)和程序環(huán)境;2)程序堆棧,它通常在程序執(zhí)行時增長,一般情況下,它向下朝堆增長。3)堆,它也在程序執(zhí)行時增長,相反,它向上朝堆棧增長;4)BSS 段,它包含未初始化的全局可用的數(shù)據(jù)(例如,全局變量); 5)數(shù)據(jù)段,它包含初始化的全局可用的數(shù)據(jù)(通常是全局變量);6)文本段,它包含只讀程序代碼。BSS、數(shù)據(jù)和文本段組成靜態(tài)內(nèi)存:在程序運行之前這些段的大小已經(jīng)固定。程序運行時雖然可以更改個別變量,但不能將數(shù)據(jù)分配到這些段中。下面以一個簡單的例子來說明以上的看起來讓人頭暈的東西:

#includestdio.h

char buf[3]="abc";

int i;

void main()

{

i=1

return;

}

其中,i屬于BBS段,而buf屬于數(shù)據(jù)段。兩者都屬于靜態(tài)內(nèi)存,因為他們在程序中雖然可以改變值,但是其分配的內(nèi)存大小是固定的,如buf的數(shù)據(jù)大于三個字符,將會覆蓋其他數(shù)據(jù)。

與靜態(tài)內(nèi)存形成對比,堆和堆棧是動態(tài)的,可以在程序運行的時候改變大小。堆的程序員接口因語言而異。在C語言中,堆是經(jīng)由 malloc() 和其它相關函數(shù)來訪問的,而C++中的new運算符則是堆的程序員接口。堆棧則比較特殊,主要是在調(diào)用函數(shù)時來保存現(xiàn)場,以便函數(shù)返回之后能繼續(xù)運行。

四、堆溢出

堆溢出的思路很簡單,覆蓋重要的變量以達到自己的目的。而在實際操作的時候,這顯得比較困難,尤其是源代碼不可見的時候。第一,你必須確定哪個變量是重要的變量;第二,你必須找到一個內(nèi)存地址比目標變量低的溢出點;第三,在特定目的下,你還必須讓在為了覆蓋目標變量而在中途覆蓋了其他變量之后,程序依然能運行下去。下面以一個源代碼看見的程序來舉例演示一次簡單的堆溢出是如何發(fā)生的:

#include "malloc.h"

#include "string.h"

#include "stdio.h"

void main()

{

char *large_str = (char *)malloc(sizeof(char)*1024);

char *important = (char *)malloc(sizeof(char)*6);

char *str = (char *)malloc(sizeof(char)*4);

strcpy(important,"abcdef");//給important賦初值

//下面兩行代碼是為了看str和important的地址

printf("%d/n",str);

printf("%d/n",important);

gets(large_str);//輸入一個字符串

strcpy(str, large_str);//代碼本意是將輸入的字符串拷貝到str

printf("%s/n",important);

}

在實際應用中,這樣的代碼當然是不存在的,這只是一個最簡單的實驗程序。現(xiàn)在我們的目標是important這個字符串變成"hacker"。str和important的地址在不同的環(huán)境中并不是一定的,我這里是7868032和7868080。很好,important的地址比str大,這就為溢出創(chuàng)造了可能。計算一下可以知道,兩者中間隔了48個字節(jié),因此在輸入溢出字符串時候,可以先輸入48個任意字符,然后再輸入hakcer回車,哈哈,出來了,important成了"hacker"。

五、堆棧溢出

堆溢出的一個關鍵問題是很難找到所謂的重要變量,而堆棧溢出則不存在這個問題,因為它將覆蓋一個非常重要的東西----函數(shù)的返回地址。在進行函數(shù)調(diào)用的時候,斷點或者說返回地址將保存到堆棧里面,以便函數(shù)結(jié)束之后繼續(xù)運行。而堆棧溢出的思路就是在函數(shù)里面找到一個溢出點,把堆棧里面的返回地址覆蓋,替換成一個自己指定的地方,而在那個地方,我們將把一些精心設計了的攻擊代碼。由于攻擊代碼的編寫需要一些匯編知識,這里我將不打算涉及。我們這里的目標是寫出一個通過覆蓋堆棧返回地址而讓程序執(zhí)行到另一個函數(shù)的堆棧溢出演示程序。

因為堆棧是往下增加的,因此,先進入堆棧的地址反而要大,這為在函數(shù)中找到溢出點提供了可能。試想,而堆棧是往上增加的,我們將永遠無法在函數(shù)里面找到一個溢出點去覆蓋返回地址。還是先從一個最簡單的例子開始:

void test(int i)

{

char buf[12];

}

void main()

{

test(1);

}

test 函數(shù)具有一個局部參數(shù)和一個靜態(tài)分配的緩沖區(qū)。為了查看這兩個變量所在的內(nèi)存地址(彼此相對的地址),我們將對代碼略作修改:

void test(int i)

{

char buf[12];

printf("i = %d/n", i);

printf("buf[0] = %d/n", buf);

}

void main()

{

test(1);

}

需要說明的是,由于個人習慣的原因,我把地址結(jié)果輸出成10進制形式,但愿這并不影響文章的敘述。在我這里,產(chǎn)生下列輸出:i = 6684072 buf[0] = 6684052。這里我補充一下,當調(diào)用一個函數(shù)的時候,首先是參數(shù)入棧,然后是返回地址。并且,這些數(shù)據(jù)都是倒著表示的,因為返回地址是4個字節(jié),所以可以知道,返回地址應該是保存在從6684068到6684071。因為數(shù)據(jù)是倒著表示的,所以實際上返回地址就是:buf[19]*256*256*256+buf[18]*256*256+buf[17]*256+buf[16]。

我們的目標還沒有達到,下面我們繼續(xù)。在上面程序的基礎,修改成:

#include stdio.h

void main()

{

void test(int i);

test(1);

}

void test(int i)

{

void come();

char buf[12];//用于發(fā)生溢出的數(shù)組

int addr[4];

int k=(int)i-(int)buf;//計算參數(shù)到溢出數(shù)組之間的距離

int go=(int)come;

//由于EIP地址是倒著表示的,所以首先把come()函數(shù)的地址分離成字節(jié)

addr[0]=(go 24)24;

addr[1]=(go 16)24;

addr[2]=(go 8)24;

addr[3]=go24;

//用come()函數(shù)的地址覆蓋EIP

for(int j=0;j4;j++)

{

buf[k-j-1]=addr[3-j];

}

}

void come()

{

printf("Success!");

}

一切搞定!運行之后,"Success!"成功打印出來!不過,由于這個程序破壞了堆棧,所以系統(tǒng)會提示程序遇到問題需要關閉。但這并不要緊,因為至少我們已經(jīng)邁出了萬里長征的第一步。

關于C語言的:一個程序的漏洞修補

我覺得這題最好用switch分支,而且既然在“printf("請選擇運算符號(1為加,2為減,3為乘,4為除,5為關閉程序),程序會自動生成一個運算數(shù)不超過2位數(shù)的算術式:"); ”輸入字母時判斷為錯誤,我覺得后面就沒有再輸入答案的必要了,所以我改為在“printf("請選擇運算符號(1為加,2為減,3為乘,4為除,5為關閉程序),程序會自動生成一個運算數(shù)不超過2位數(shù)的算術式:"); ”前加一個" Loop:",把continue改為goto Loop;雖然在C中goto語句最好不使用,但我覺得這題足??!

為什么C語言的strcpy函數(shù)有漏洞

strcpy將源字符串拷貝到目標字符串時,并不檢查目標字符串的長度,如果源字符串過長會導致目標內(nèi)存后面的空間被覆蓋

關于c語言printf 與scanf問題 漏洞

這個是可以實現(xiàn)的,這樣就行。#include#include#include#includeintmain(){intn;printf("請輸入數(shù)字:【】\b\b");scanf("%d",n);}\b是退格符號。因為“【】”是中文符號,所以占得字節(jié)數(shù)與英文字符不一樣。你自己可以調(diào)一下格式。而且這兒還有一個關鍵的問題,就是當“【】”內(nèi)的內(nèi)容夠長時,就會把后面的括號“】”覆蓋掉。你可以自己試一下

新聞標題:c語言有漏洞的接口函數(shù),C語言漏洞
文章路徑:http://www.muchs.cn/article14/hcphge.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供虛擬主機網(wǎng)站營銷、靜態(tài)網(wǎng)站面包屑導航、網(wǎng)站策劃、商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設計公司