溢出是程序設(shè)計(jì)者設(shè)計(jì)時(shí)的不足所帶來的錯(cuò)誤。溢出是黑客利用操作系統(tǒng)的漏洞,專門開發(fā)了一種程序,加相應(yīng)的參數(shù)運(yùn)行后,就可以得到用戶電腦具有管理員資格的控制權(quán),用戶在自己電腦上能夠運(yùn)行的東西他可以全部做到,等于用戶的電腦就是他的了。溢出可分為緩沖區(qū)溢出、內(nèi)存溢出、數(shù)據(jù)溢出等多類,使緩沖區(qū)溢出的任何嘗試通常都會被該語言本身自動檢測并阻止。
溢出_溢出 -基本介紹
溢出
溢出是在你自己電腦上能夠運(yùn)行的東西他可以全部做到,等于你的電腦就是他的了。在黑客頻頻攻擊、在系統(tǒng)漏洞層出不窮的今天,作為網(wǎng)絡(luò)管理員、系統(tǒng)管理員的我們雖然在服務(wù)器的安全上都下了不少功夫:諸如,及時(shí)的打上系統(tǒng)安全補(bǔ)丁、進(jìn)行一些常規(guī)的安全配置,但是仍然不太可能每臺服務(wù)器都會在第一時(shí)間內(nèi)給系統(tǒng)打上全新補(bǔ)丁。因此我們必需要在還未被入侵之前,通過一些系列安全設(shè)置,來將入侵者們擋在“安全門”之外。
溢出_溢出 -溢出分類
1.1在程序的地址空間里安排適當(dāng)?shù)拇a
1.1.1殖入法
攻擊者用被攻擊程序的緩沖區(qū)來存放攻擊代碼。 攻擊者向被攻擊的程序輸入一個(gè)字符串,程序會把這個(gè)字符串放到緩沖區(qū)里。這個(gè)字符串包含的數(shù)據(jù)是可以在這個(gè)被攻擊的硬件平臺上運(yùn)行的指令序列。
1.1.2利用已經(jīng)存在的代碼
有時(shí)候,攻擊者想要的代碼已經(jīng)在被攻擊的程序中了,攻擊者所要做的只是對代碼傳遞一些參數(shù),然后使程序跳轉(zhuǎn)到指定目標(biāo)。比如,在C語言中,攻擊代碼要求執(zhí)行“exec("/bin/sh")”,而在libc庫中的代碼執(zhí)行“exec(arg)”,其中arg是指向一個(gè)字符串的指針參數(shù),那么攻擊者只要把傳入的參數(shù)指針指向"/bin/sh",就可以調(diào)轉(zhuǎn)到libc庫中的相應(yīng)的指令序列。
1.2控制程序轉(zhuǎn)移到攻擊代碼
這種方法旨在改變程序的執(zhí)行流程,使之跳轉(zhuǎn)到攻擊代碼。最基本方法的就是溢出一個(gè)沒有邊界檢查或者其他弱點(diǎn)的緩沖區(qū),這樣就擾亂了程序的正常的執(zhí)行順序。通過溢出一個(gè)緩沖區(qū),攻擊者可以用近乎暴力的方法改寫相鄰的程序空間而直接跳過了系統(tǒng)的檢查。
1.2.1激活紀(jì)錄(Activation Records)
每當(dāng)一個(gè)函數(shù)調(diào)用發(fā)生時(shí),調(diào)用者會在堆棧中留下一個(gè)激活紀(jì)錄,它包含了函數(shù)結(jié)束時(shí)返回的地址。攻擊者通過溢出這些自動變量,使這個(gè)返回地址指向攻擊代碼。通過改變程序的返回地址,當(dāng)函數(shù)調(diào)用結(jié)束時(shí),程序就跳轉(zhuǎn)到攻擊者設(shè)定的地址,而不是原先的地址。這類的緩沖區(qū)溢出被稱為“stack smashing attack”,是目前常用的緩沖區(qū)溢出攻擊方式。
1.2.2函數(shù)指針(Function Pointers)

C語言中,“void (* foo)()”聲明了一個(gè)返回值為void函數(shù)指針的變量foo。函數(shù)指針可以用來定位任何地址空間,所以攻擊者只需在任何空間內(nèi)的函數(shù)指針附近找到一個(gè)能夠溢出的緩沖區(qū),然后溢出這個(gè)緩沖區(qū)來改變函數(shù)指針。在某一時(shí)刻,當(dāng)程序通過函數(shù)指針調(diào)用函數(shù)時(shí),程序的流程就按攻擊者的意圖實(shí)現(xiàn)了!它的一個(gè)攻擊范例就是在Linux系統(tǒng)下的super probe程序。
1.2.3長跳轉(zhuǎn)緩沖區(qū)(Longjmp buffers)
在C語言中包含了一個(gè)簡單的檢驗(yàn)/恢復(fù)系統(tǒng),稱為setjmp/longjmp。意思是在檢驗(yàn)點(diǎn)設(shè)定“setjmp(buffer)”,用“l(fā)ongjmp(buffer)”來恢復(fù)檢驗(yàn)點(diǎn)。然而,如果攻擊者能夠進(jìn)入緩沖區(qū)的空間,那么“l(fā)ongjmp(buffer)”實(shí)際上是跳轉(zhuǎn)到攻擊者的代碼。象函數(shù)指針一樣,longjmp緩沖區(qū)能夠指向任何地方,所以攻擊者所要做的就是找到一個(gè)可供溢出的緩沖區(qū)。一個(gè)典型的例子就是Perl 5.003,攻擊者首先進(jìn)入用來恢復(fù)緩沖區(qū)溢出的的longjmp緩沖區(qū),然后誘導(dǎo)進(jìn)入恢復(fù)模式,這樣就使Perl的解釋器跳轉(zhuǎn)到攻擊代碼上了!
最簡單和常見的緩沖區(qū)溢出攻擊類型就是在一個(gè)字符串里綜合了代碼殖入和激活紀(jì)錄。攻擊者定位一個(gè)可供溢出的自動變量,然后向程序傳遞一個(gè)很大的字符串,在引發(fā)緩沖區(qū)溢出改變激活紀(jì)錄的同時(shí)殖入了代碼。這個(gè)是由Levy指出的攻擊的模板。因?yàn)镃語言在習(xí)慣上只為用戶和參數(shù)開辟很小的緩沖區(qū),因此這種漏洞攻擊的實(shí)例不在少數(shù)。
代碼殖入和緩沖區(qū)溢出不一定要在一次動作內(nèi)完成。攻擊者可以在一個(gè)緩沖區(qū)內(nèi)放置代碼,這是不能溢出緩沖區(qū)。然后,攻擊者通過溢出另外一個(gè)緩沖區(qū)來轉(zhuǎn)移程序的指針。這種方法一般用來解決可供溢出的緩沖區(qū)不夠大的情況。
如果攻擊者試圖使用已經(jīng)常駐的代碼而不是從外部殖入代碼,他們通常有必須把代碼作為參數(shù)化。舉例來說,在libc中的部分代碼段會執(zhí)行“exec(something)”,其中something就是參數(shù)。攻擊者然后使用緩沖區(qū)溢出改變程序的參數(shù),利用另一個(gè)緩沖區(qū)溢出使程序指針指向libc中的特定的代碼段。
為什么緩沖區(qū)溢出如此常見
在幾乎所有計(jì)算機(jī)語言中,不管是新的語言還是舊的語言,使緩沖區(qū)溢出的任何嘗試通常都會被該語言本身自動檢測并阻止(比如通過引發(fā)一個(gè)異?;蚋鶕?jù)需要給緩沖區(qū)添加更多空間)。但是有兩種語言不是這樣:C 和 C++ 語言。C 和 C++ 語言通常只是讓額外的數(shù)據(jù)亂寫到其余內(nèi)存的任何位置,而這種情況可能被利用從而導(dǎo)致恐怖的結(jié)果。更糟糕的是,用 C 和 C++ 編寫正確的代碼來始終如一地處理緩沖區(qū)溢出則更為困難;很容易就會意外地導(dǎo)致緩沖區(qū)溢出。除了 C 和 C++ 使用得 非常廣泛外,上述這些可能都是不相關(guān)的事實(shí);例如,Red Hat Linux 7.1 中 86% 的代碼行都是用 C 或 C ++ 編寫的。因此,大量的代碼對這個(gè)問題都是脆弱的,因?yàn)閷?shí)現(xiàn)語言無法保護(hù)代碼避免這個(gè)問題。
在 C 和 C++ 語言本身中,這個(gè)問題是不容易解決的。該問題基于 C 語言的根本設(shè)計(jì)決定(特別是 C 語言中指針和數(shù)組的處理方式)。由于 C++ 是最兼容的 C 語言超集,它也具有相同的問題。存在一些能防止這個(gè)問題的 C/C++ 兼容版本,但是它們存在極其嚴(yán)重的性能問題。而且一旦改變 C 語言來防止這個(gè)問題,它就不再是 C 語言了。許多語言(比如 Java 和 C#)在語法上類似 C,但它們實(shí)際上是不同的語言,將現(xiàn)有 C 或 C++ 程序改為使用那些語言是一項(xiàng)艱巨的任務(wù)。
然而,其他語言的用戶也不應(yīng)該沾沾自喜。有些語言存在允許緩沖區(qū)溢出發(fā)生的“轉(zhuǎn)義”子句。Ada 一般會檢測和防止緩沖區(qū)溢出(即針對這樣的嘗試引發(fā)一個(gè)異常),但是不同的程序可能會禁用這個(gè)特性。C# 一般會檢測和防止緩沖區(qū)溢出,但是它允許程序員將某些例程定義為“不安全的”,而這樣的代碼 可能 會導(dǎo)致緩沖區(qū)溢出。因此如果您使用那些轉(zhuǎn)義機(jī)制,就需要使用 C/C++ 程序所必須使用的相同種類的保護(hù)機(jī)制。許多語言都是用 C 語言來實(shí)現(xiàn)的(至少部分是用 C 語言來實(shí)現(xiàn)的 ),并且用任何語言編寫的所有程序本質(zhì)上都依賴用 C 或 C++ 編寫的庫。因此,所有程序都會繼承那些問題,所以了解這些問題是很重要的。
防止緩沖區(qū)溢出的新技術(shù)
當(dāng)然,要讓程序員 不犯常見錯(cuò)誤是很難的,而讓程序(以及程序員)改為使用另一種語言通常更為困難。那么為何不讓底層系統(tǒng)自動保護(hù)程序避免這些問題呢?最起碼,避免 stack-smashing 攻擊是一件好事,因?yàn)?stack-smashing 攻擊是特別容易做到的。
一般來說,更改底層系統(tǒng)以避免常見的安全問題是一個(gè)極好的想法,我們在本文后面也會遇到這個(gè)主題。事實(shí)證明存在許多可用的防御措施,而一些最受歡迎的措施可分組為以下類別:
基于探測方法(canary)的防御。這包括 StackGuard(由 Immunix 所使用)、ProPolice(由 OpenBSD 所使用)和 Microsoft 的 /GS 選項(xiàng)。
非執(zhí)行的堆棧防御。這包括 Solar Designer 的 non-exec 補(bǔ)?。ㄓ?OpenWall 所使用)和 exec shield(由 Red Hat/Fedora 所使用)。
其他方法。這包括 libsafe(由 Mandrake 所使用)和堆棧分割方法。
遺憾的是,迄今所見的所有方法都具有弱點(diǎn),因此它們不是萬能藥,但是它們會提供一些幫助。
▲基于探測方法的防御
研究人員 Crispen Cowan 創(chuàng)建了一個(gè)稱為 StackGuard 的有趣方法。Stackguard 修改 C 編譯器(gcc),以便將一個(gè)“探測”值插入到返回地址的前面?!疤綔y儀”就像煤礦中的探測儀:它在某個(gè)地方出故障時(shí)發(fā)出警告。在任何函數(shù)返回之前,它執(zhí)行檢查以確保探測值沒有改變。如果攻擊者改寫返回地址(作為 stack-smashing 攻擊的一部分),探測儀的值或許就會改變,系統(tǒng)內(nèi)就會相應(yīng)地中止。這是一種有用的方法,不過要注意這種方法無法防止緩沖區(qū)溢出改寫其他值(攻擊者仍然能夠利用這些值來攻擊系統(tǒng))。人們也曾擴(kuò)展這種方法來保護(hù)其他值(比如堆上的值)。Stackguard(以及其他防御措施)由 Immunix 所使用。
IBM 的 stack-smashing 保護(hù)程序(ssp,起初名為 ProPolice)是 StackGuard 的方法的一種變化形式。像 StackGuard 一樣,ssp 使用一個(gè)修改過的編譯器在函數(shù)調(diào)用中插入一個(gè)探測儀以檢測堆棧溢出。然而,它給這種基本的思路添加了一些有趣的變化。 它對存儲局部變量的位置進(jìn)行重新排序,并復(fù)制函數(shù)參數(shù)中的指針,以便它們也在任何數(shù)組之前。這樣增強(qiáng)了ssp 的保護(hù)能力;它意味著緩沖區(qū)溢出不會修改指針值(否則能夠控制指針的攻擊者就能使用指針來控制程序保存數(shù)據(jù)的位置)。默認(rèn)情況下,它不會檢測所有函數(shù),而只是檢測確實(shí)需要保護(hù)的函數(shù)(主要是使用字符數(shù)組的函數(shù))。從理論上講,這樣會稍微削弱保護(hù)能力,但是這種默認(rèn)行為改進(jìn)了性能,同時(shí)仍然能夠防止大多數(shù)問題??紤]到實(shí)用的因素,它們以獨(dú)立于體系結(jié)構(gòu)的方式使用 gcc 來實(shí)現(xiàn)它們的方法,從而使其更易于運(yùn)用。從 2003 年 5 月的發(fā)布版本開始,廣受贊譽(yù)的 OpenBSD(它重點(diǎn)關(guān)注安全性)在他們的整個(gè)發(fā)行套件中使用了 ssp(也稱為 ProPolice)。
Microsoft 基于 StackGuard 的成果,添加了一個(gè)編譯器標(biāo)記(/GS)來實(shí)現(xiàn)其 C 編譯器中的探測儀。
▲非執(zhí)行的堆棧防御
另一種方法首先使得在堆棧上執(zhí)行代碼變得不可能。 遺憾的是,x86 處理器(最常見的處理器)的內(nèi)存保護(hù)機(jī)制無法容易地支持這點(diǎn);通常,如果一個(gè)內(nèi)存頁是可讀的,它就是可執(zhí)行的。一個(gè)名叫 Solar Designer 的開發(fā)人員想出了一種內(nèi)核和處理器機(jī)制的聰明組合,為 Linux 內(nèi)核創(chuàng)建了一個(gè)“非執(zhí)行的堆棧補(bǔ)丁”;有了這個(gè)補(bǔ)丁,堆棧上的程序就不再能夠像通常的那樣在 x86 上運(yùn)行。 事實(shí)證明在有些情況下,可執(zhí)行程序 需要在堆棧上;這包括信號處理和跳板代碼(trampoline)處理。trampoline 是有時(shí)由編譯器(比如 GNAT Ada 編譯器)生成的奇妙結(jié)構(gòu),用以支持像嵌套子例程之類的結(jié)構(gòu)。Solar Designer 還解決了如何在防止攻擊的同時(shí)使這些特殊情況不受影響的問題。
Linux 中實(shí)現(xiàn)這個(gè)目的的最初補(bǔ)丁在 1998 年被 Linus Torvalds 拒絕,這是因?yàn)橐粋€(gè)有趣的原因。即使不能將代碼放到堆棧上,攻擊者也可以利用緩沖區(qū)溢出來使程序“返回”某個(gè)現(xiàn)有的子例程(比如 C 庫中的某個(gè)子例程),從而進(jìn)行攻擊。簡而言之,僅只是擁有非可執(zhí)行的堆棧是不足夠的。
一段時(shí)間之后,人們又想出了一種防止該問題的新思路:將所有可執(zhí)行代碼轉(zhuǎn)移到一個(gè)稱為“ASCII 保護(hù)(ASCII armor)”區(qū)域的內(nèi)存區(qū)。要理解這是如何工作的,就必須知道攻擊者通常不能使用一般的緩沖區(qū)溢出攻擊來插入 ASCII NUL 字符(0)這個(gè)事實(shí)。 這意味著攻擊者會發(fā)現(xiàn),要使一個(gè)程序返回包含 0 的地址是很困難的。由于這個(gè)事實(shí),將所有可執(zhí)行代碼轉(zhuǎn)移到包含 0 的地址就會使得攻擊該程序困難多了。
具有這個(gè)屬性的最大連續(xù)內(nèi)存范圍是從 0 到 0x01010100 的一組內(nèi)存地址,因此它們就被命名為 ASCII 保護(hù)區(qū)域(還有具有此屬性的其他地址,但它們是分散的)。與非可執(zhí)行的堆棧相結(jié)合,這種方法就相當(dāng)有價(jià)值了:非可執(zhí)行的堆棧阻止攻擊者發(fā)送可執(zhí)行代碼,而 ASCII 保護(hù)內(nèi)存使得攻擊者難于通過利用現(xiàn)有代碼來繞過非可執(zhí)行堆棧。這樣將保護(hù)程序代碼避免堆棧、緩沖區(qū)和函數(shù)指針溢出,而且全都不需重新編譯。
然而,ASCII 保護(hù)內(nèi)存并不適用于所有程序;大程序也許無法裝入 ASCII 保護(hù)內(nèi)存區(qū)域(因此這種保護(hù)是不完美的),而且有時(shí)攻擊者 能夠?qū)?0 插入目的地址。 此外,有些實(shí)現(xiàn)不支持跳板代碼,因此可能必須對需要這種保護(hù)的程序禁用該特性。Red Hat 的 Ingo Molnar 在他的“exec-shield”補(bǔ)丁中實(shí)現(xiàn)了這種思想,該補(bǔ)丁由 Fedora 核心(可從 Red Hat 獲得它的免費(fèi)版本)所使用。最新版本的 OpenWall GNU/Linux (OWL)使用了 Solar Designer 提供的這種方法的實(shí)現(xiàn)(請參閱 參考資料 以獲得指向這些版本的鏈接)。
▲其他方法
還有其他許多方法。一種方法就是使標(biāo)準(zhǔn)庫對攻擊更具抵抗力。Lucent Technologies 開發(fā)了 Libsafe,這是多個(gè)標(biāo)準(zhǔn) C 庫函數(shù)的包裝,也就是像 strcpy() 這樣已知的對 stack-smashing 攻擊很脆弱的函數(shù)。Libsafe 是在 LGPL 下授予許可證的開放源代碼軟件。那些函數(shù)的 libsafe 版本執(zhí)行相關(guān)的檢查,確保數(shù)組改寫不會超出堆棧楨。然而,這種方法僅保護(hù)那些特定的函數(shù),而不是從總體上防止堆棧溢出缺陷,并且它僅保護(hù)堆棧,而不保護(hù)堆棧中的局部變量。它們的最初實(shí)現(xiàn)使用了 LD_PRELOAD ,而這可能與其他程序產(chǎn)生沖突。Linux 的 Mandrake 發(fā)行套件(從 7.1 版開始)包括了 libsafe。
另一種方法稱為“分割控制和數(shù)據(jù)堆?!?/p>
愛華網(wǎng)本文地址 » http://www.klfzs.com/a/8103450103/101151.html
愛華網(wǎng)



