為什麼會出現緩衝區溢位
出現緩衝區溢位需要具備很多條件,包括:
現在我們來仔細看看以上每種條件。
首先,緩衝區溢位主要出現在 c 和 c++ 中,因為這些語言不執行陣列邊界檢查和型別安全檢查。c/c++ 允許開發人員建立非常接近硬體執行的程式,從而允許直接訪問記憶體和計算機暫存器。其結果可以獲得優異的效能;很難有任何應用程式能象編寫得很好的 c/c++ 應用程式執行得那樣快。其他語言中也會出現緩衝區溢位,但很少見。如果出現這種錯誤,通常不是由開發人員造成的,而是執行時環境的錯誤。
其次,如果應用程式從使用者(或攻擊者)那裡獲取資料,並將資料複製到應用程式所維護的緩衝區中而未考慮目標緩衝區的大小,則可能造成緩衝區溢位。換句話說,**為緩衝區分配了 n 個位元組,卻將多於 n 個位元組的資料複製到該緩衝區中。這就象向 12 盎司的玻璃杯中注入 16 盎司的水一樣。那麼多出的 4 盎司水到**去了呢?全溢位去了!
最後一點,也是最重要的一點,編譯器通常將緩衝區放在「令人感興趣的」資料結構旁邊。例如,當某個函式的緩衝區緊鄰堆疊,則在記憶體中該函式的返回位址緊靠在緩衝區之後。這時,如果攻擊者可以使該緩衝區發生溢位,他就可以覆蓋函式的返回位址,從而在返回函式時,返回到攻擊者定義的位址。其他令人感興趣的資料結構包括 c++ v 表、異常處理程式位址、函式指標等等。
下面我們來看乙個示例。
以下**有什麼錯誤?
令人驚訝的是,這段**可能沒有什麼錯誤!這完全取決於 copydata() 的呼叫方式。例如,以下**是安全的:
這段**是安全的,因為名字是硬編碼的,並且知道每個字串在長度上不超過 32 個字元,因此呼叫 strcpy 永遠是安全的。然而,如果 copydata 和 szdata 的唯一引數來自不可靠的源(如套接字或檔案),則 strcpy 將複製該資料,直到碰到空字元為止;如果此資料的長度大於 32 個字元,則 cdest 緩衝區將溢位,並且在記憶體中該緩衝區以外的任何資料將遭到破壞。不幸的是,在這裡,遭到破壞的資料是來自 copydata 的返回位址,這意味著當 copydata 完成時,它仍然在由攻擊者指定的位置繼續執行。這真糟糕!
其他資料結構也同樣敏感。假設某個 c++ 類的 v 表遭到破壞,如下面這段**:
此示例假定 cfoo 類具有虛方法,以及乙個 v 表或該類方法的位址列表(與所有 c++ 類一樣)。如果由於 cdest 緩衝區被覆蓋而破壞了 v 表,則該類的任何虛方法(在此例中是 init() )都可能呼叫攻擊者指定的位址,而不是 init() 的位址。順便說一句,如果認為您的**不呼叫任何 c++ 方法就安全了,那就錯了,因為有乙個方法始終會被呼叫,即該類的虛析構函式!當然,如果某個類不呼叫任何方法,就應該想想它存在的必要了。
現在,我們繼續討論一些更實際的內容 - 如何在您的**中刪除和防止緩衝區溢位。
在 2002 年 2 月和 3 月,我們舉辦了 microsoft windows security push 活動。在此期間,我的工作組對 8,500 多位人員在設計、編寫、測試和記錄安全功能方面進行了培訓。我們為所有設計人員提出的乙個建議就是,制定計畫,將相應的應用程式和工具從本機 win32 c++ **遷移到託管**。這樣做有多種原因,主要是有助於減少緩衝區溢位。在託管**中,很難建立出包含緩衝區溢位的**,因為所編寫的**不能直接訪問指標、計算機暫存器或記憶體。您應當考慮,或者至少要計畫將某些應用程式和工具遷移到託管**中。例如,管理工具就是乙個很好的遷移物件。當然,我們也要現實一些,因為不可能在乙個晚上將所有的應用程式從 c++ 遷移到 c# 或其他託管語言中。
當編寫 c 和 c++ **時,應注意如何管理來自使用者的資料。如果某個函式具有來自不可靠源的緩衝區,請遵循以下規則:
現在我們來仔細看看以上每種情況。
如果任何函式呼叫具有類似特徵,將出現乙個錯誤:
此**的問題在於函式不能判斷 szname 的長度,這意味著將不能安全地複製資料。函式應知道 szname 的大小:
然而,您不能想當然地信任 cbname 。攻擊者可以設定該名稱和緩衝區大小,因此必須進行檢查!
如何判別 szname 和 cbname 是有效的?您相信使用者會提供有效的值嗎?一般來說,答案是否定的。驗證緩衝區大小是否有效的乙個簡單方法是探測記憶體。以下**段顯示了如何在**的除錯版中完成這一驗證過程:
此**將嘗試向目標緩衝區寫入值 0x42。您可能會想,為什麼要這樣做而不是直接複製緩衝區呢?通過向目標緩衝區的末尾寫入乙個固定的已知值,可以在源緩衝區太大時,強制**失敗。同時這樣也可以在開發過程中及早發現開發錯誤。與其執行攻擊者的惡意有效**,還不如讓程式失敗。這就是不複製攻擊者的緩衝區的原因。
注意:您只能在除錯版中這樣做,以便在測試過程中捕獲緩衝區溢位。
說實話,探測雖然很有用,但它並不能使您免遭攻擊。真正安全的辦法是編寫防範性的**。您會注意到**已經具有防範性了。它將檢查進入函式的資料是否不超過內部緩衝區 szbuff 。然而,有些函式在處理或複製不可靠的資料時,如果使用不當,則會存在潛在的嚴重安全問題。這裡的關鍵是不可靠的資料。在檢查**的緩衝區溢位錯誤時,應跟蹤資料在**中的流向,並檢查各種資料假設。當您意識到有些假設不正確時,您也許會驚異於所發現的錯誤。
需要注意的函式包括諸如 strcpy、strcat、gets 等常見函式。但也不能排除所謂的 strcpy 和 strcat 的「安全的 n 版本」- strncpy 和 strncat。這些函式被認為使用起來更安全、可靠,因為它們允許開發人員限制複製到目標緩衝區中的資料的大小。然而,開發人員在使用這些函式時也會出錯!請看以下這段**。您能看出其中的缺點嗎?
如果您需要提示,請注意每個字串處理函式的最後乙個引數。要放棄嗎?在我給出答案之前,我經常會開玩笑說,如果您禁用「不安全」的字串處理函式,而使用較為安全的 n 版本,則恐怕您要在修復新產生的錯誤中度過您的餘生。以下便是原因所在。首先,最後那個引數不是目標緩衝區的總體大小。它是緩衝區剩餘空間的大小,**每次向 buff 新增內容時,buff 都會有實質的減小。第二個問題是,即使使用者傳遞了緩衝區大小,他們通常也是逐一減小的。那麼在計算字串大小時,您有沒有包含末尾的空字元?當我針對這個問題進行讀者調查時,通常是對半分。其中一半認為在計算緩衝區大小時確實要考慮末尾空字元,另外一半則不這麼認為。第三,在某些情況下,n 版本可能不會以空字元作為結果字串的結束字元,因此請一定要閱讀文件。
如果編寫 c++ **,請考慮使用 atl、stl、mfc 或者您最喜歡的字串處理類來處理字串,而不要直接處理位元組。唯一潛在的不足是可能出現效能的下降,但總的來說,大部分這些類的使用都會使**更加強大和可維護。
visual c++ .net 中的這個新的編譯時選項會在某些函式的堆疊框架中插入值,有助於減少基於堆疊的緩衝區溢位的潛在弱點。請記住,此選項不會修復您的**,也不能刪除任何錯誤。它只是象乙個棒球運動的捕手,幫助您減少某些類的緩衝區溢位變為可被人利用的緩衝區溢位的潛在可能性,以免攻擊者向過程中寫入**並執行。可以把它視為乙個很小的保險措施。請注意,對於使用 win32 應用程式嚮導建立的新的本機 win32 c++ 專案,將預設啟用此選項。此外,windows .net server 編譯時也使用了此選項。有關詳細資訊,請參閱 brandon bray 的 compiler security checks in depth(英文)。
michael howard是 microsoft secure windows initiative 小組的安全程式經理,也是《writing secure code》的作者之一。他的主要工作就是確保人們設計、構建、測試和記錄無缺陷的安全系統。他最喜歡的話是「尺有所短,寸有所長」。
< 本文**hellocpp >
緩衝區溢位問題
1.什麼是緩衝區溢位 緩衝區溢位是一種非常普遍 非常危險的漏洞,在各種作業系統 應用軟體中廣泛存在。利用緩衝區溢位 攻擊,可以導致程式執行失敗 系統宕機 重新啟動等後果。更為嚴重的是,可以利用它執行非授權指 令,甚至可以取得系統特權,進而進行各種非法操作。緩衝區溢位 buffer overflow ...
緩衝區溢位
緩衝區溢位是指當電腦程式向緩衝區內填充的資料位數超過了緩衝區本身的容量。溢位的資料覆蓋在合法資料上。理想情況是,程式檢查資料長度並且不允許輸入超過緩衝區長度的字串。但是絕大多數程式都會假設資料長度總是與所分配的儲存空間相匹配,這就為緩衝區溢位埋下隱患。作業系統所使用的緩衝區又被稱為堆疊,在各個操作程...
緩衝區溢位
緩衝區溢位,簡單的說就是計算機對接收的輸入資料沒有進行有效的檢測 理想的情況是程式檢查資料長度並不允許輸入超過緩衝區長度的字元 向緩衝區內填充資料時超過了緩衝區本身的容量,而導致資料溢位到被分配空間之外的記憶體空間,使得溢位的資料覆蓋了其他記憶體空間的資料。通過往程式的緩衝區寫超出其長度的內容,造成...