- C和C++安全編碼(原書第2版)
- (美)Robert C.Seacord
- 1571字
- 2020-10-30 17:56:41
2.3.6 棧溢出
當緩沖區溢出覆寫分配給執行棧內存中的數據時,就會導致棧溢出(stack smashing)。這種情況會對程序的可靠性和安全性造成嚴重的后果。stack段的緩沖區溢出使得攻擊者能夠修改自動變量的值或執行任意的代碼。
覆寫自動變量會破壞數據的完整性,在某些情況下也可能會引發安全漏洞(例如,在一個包含用戶ID或密碼的變量被覆寫的情況下)。更常見的情況是,stack段的緩沖區溢出可能會允許攻擊者通過覆寫指向控制被(最終)轉移的地址的指針來執行任意的代碼,一個常見的例子是覆寫返回地址(該地址也位于棧中)。此外,還可能覆寫基于幀或基于棧的異常處理指針、函數指針或其他控制將會轉移到的地址。
IsPasswordOK()程序示例容易遭受棧溢出攻擊。要理解為何這個程序有漏洞,首先必須理解棧究竟是如何被使用的。程序在調用IsPasswordOK()之前,棧中包含的信息如圖2.8所示。
圖2.8 調用IsPasswordOK()之前的棧信息
操作系統(OS)或標準的啟動序列把從main()的返回地址壓入棧。在入口處,main()函數保存舊的傳入幀指針,而這又來自操作系統或標準的啟動序列。在調用IsPasswordOK()函數之前,棧包含局部布爾變量PwStatus,它保存由函數IsPasswordOK()返回的狀態,此外,棧還包含調用者的幀指針和返回地址。
當程序執行IsPasswordOK()函數時,棧中包含的信息如圖2.9所示。
圖2.9 IsPasswordOK()執行時棧中的信息
請注意,Password數組和main()函數的返回地址都位于棧中,并且main()函數的返回地址的位置位于Password數組之后。理解在調用IsPasswordOK()的過程中棧會發生變化是非常重要的。當程序從IsPasswordOK()返回時,棧恢復到原來的狀態,如圖2.10所示。
圖2.10 棧恢復到初始狀態
main()函數繼續執行,執行哪個分支取決于從IsPasswordOK()函數返回的值。
安全漏洞:IsPasswordOK()。如前所言,由于Password數組只能包含最多11個字符加上結尾的空字符,因此IsPasswordOK()程序存在一個安全缺陷。如圖2.11所示,可以通過輸入“12345678901234567890”這樣的有著20個字符的密碼,造成程序崩潰,從而很容易地暴露這個缺陷。
圖2.11 如果超出其字符限制,未正確地限定邊界的Password數組導致程序崩潰
要弄清楚程序崩潰的原因,首先必須理解在一個12字節的棧變量中保存20個字節長的密碼會造成什么樣的影響。由于20個字節是用戶輸入的,加上用作結尾的空字符,因此實際上存儲該字符串所需要的內存是21個字節。但是,由于可用于存儲密碼的空間僅為12字節,因此棧中用來存儲其他信息的9個字節(21–12=9)就被密碼數據覆寫了。圖2.12展示了當調用gets()讀取20個字節的密碼以及溢出所分配的緩沖區后,被擾攪亂的程序棧。請注意,調用者的幀指針、返回地址以及PwStatus變量的一部分存儲空間都已經被破壞了。
當一個程序發生故障時,一般的用戶通常并不會想到程序可能存在漏洞。他們只會想到重啟程序,但是,攻擊者會繼續研究,以查看程序的缺陷是否可被利用。
程序崩潰是因為緩沖區溢出導致返回地址被修改了,而新的地址要么是無效的,要么該地址的內存屬于下列情況:(1)未包含有效的CPU指令;(2)雖然包含有效的指令,但是CPU的寄存器并沒有為指令的正確執行做出正確的設置;或者(3)不可執行。
圖2.12 損壞的程序棧
如圖2.13所示,一段精心設計的輸入字符串可以讓程序產生意外的結果。
圖2.14展示了當輸入字符串溢出為Password分配的存儲空間時,棧的內容是如何改變的。輸入字符串包含一些看起來比較有趣的字符“j%*!”。這些都是可以利用鍵盤或者字符映射表(character map)輸入的、可顯示的ASCII字符。每一個字符都有一個對應的十六進制值:‘j’=0x6A,‘%’=0x10,‘*’=0x2A,‘!’=0x21。在內存中,這個4字符序列對應于一個4字節的地址,而這個地址覆蓋了棧中原來的返回地址,所以IsPasswordOK()函數不是返回到main()中緊隨此調用的指令,而是將控制返回給“授予訪問”分支,這就使得攻擊者繞過了執行密碼驗證邏輯的那段代碼,從而獲得對系統的訪問權限。這種攻擊是一個簡單的弧注入攻擊。弧注入攻擊在2.3.8節中有更詳細的描述。
圖2.13 一個精心制作的輸入字符串導致的意外結果
圖2.14 使用一個精心設計的輸入字符串導致緩沖區溢出后的程序棧
- 極簡算法史:從數學到機器的故事
- 計算思維與算法入門
- Java Web開發學習手冊
- 自己動手寫Java虛擬機
- 看透JavaScript:原理、方法與實踐
- Android Native Development Kit Cookbook
- 深入理解Android:Wi-Fi、NFC和GPS卷
- Learning Raspbian
- Protocol-Oriented Programming with Swift
- R語言與網絡輿情處理
- Python Data Science Cookbook
- 編程改變生活:用Python提升你的能力(進階篇·微課視頻版)
- Practical Microservices
- Arduino Wearable Projects
- PowerDesigner 16 從入門到精通