什麼是緩衝區溢位

寫入超過陣列等區域(緩衝區)大小的資料,破壞相鄰記憶體的情形。在C語言中,容易發生在 strcpy 或 gets 這類不知道寫入目的地大小的函式,或不檢查範圍就使用索引的迴圈中,屬於未定義行為。堆疊上的緩衝區溢位時,區域變數或函式的返回位址會被改寫,可能被利用於透過外部輸入執行任意程式碼的攻擊。以可指定大小的函式與範圍檢查來預防。

日文名稱: バッファオーバーフロー

「緩衝區溢位」出現在2領域的3道練習題中(連結器與載入器與執行檔格式, C語言基礎等)。

這個名詞所屬的領域: C語言基礎

常見原因

典型的錯誤有:忘了計算結尾 '\0' 的1位元組,而以 strcpy 把8個字元複製到 char name[8];不檢查長度就以 gets 或 scanf("%s") 讀取輸入;像 for (i = 0; i <= N; i++) 這樣多寫一個元素等。使用不接收寫入目的地大小的函式時,寫入多少是由輸入的資料決定的。

被攻擊利用與防禦機制

堆疊上的緩衝區附近保存著函式的返回位址。攻擊者以很長的輸入改寫它,把執行轉移到事先準備的程式碼或函式庫的函式。作業系統與編譯器以檢查放在返回位址前之值是否改變的堆疊保護(canary)、寫入與執行的分離(W^X)、位址隨機化(ASLR)等,讓攻擊更困難。

在程式中的預防方法

以 snprintf 這類可指定寫入大小的函式取代 strcpy,並一定要檢查輸入長度與索引範圍。開發期間加上 -fsanitize=address(AddressSanitizer),可在執行時偵測範圍外的寫入。在沒有MMU的微控制器上,溢位不會立即停止程式,而是默默破壞相鄰的資料,因此要特別注意。

練習緩衝區溢位的題目

關於ASLR(位址空間配置隨機化)的目的,下列何者正確?

  1. A每次執行時改變堆疊、堆積、函式庫等的位址,使攻擊者難以預測所瞄準的位址
  2. B隨機選擇記憶體位址,以提高快取命中率
  3. C隨機釋放未使用的記憶體,以增加可用容量
查看答案與解析

正確答案:A. 每次執行時改變堆疊、堆積、函式庫等的位址,使攻擊者難以預測所瞄準的位址

在利用緩衝區溢位等的攻擊中,知道函式庫函式與堆疊上資料的位址相當重要。ASLR會在每次啟動行程時,將堆疊、堆積、共用函式庫、執行檔的放置位址錯開,讓攻擊者無法預先鎖定位址。它單獨並不能完全防禦,需與寫入與執行分離等其他對策搭配使用。

藉由不讓記憶體分頁同時具備「可寫入」與「可執行」(W^X,寫入與執行分離),較容易防禦的攻擊為下列何者?

  1. A以暴力法逐一嘗試密碼的攻擊
  2. B傳送大量通訊使伺服器停擺的攻擊
  3. C將攻擊用的機器碼寫入堆疊等資料區域,並跳到那裡執行的攻擊
查看答案與解析

正確答案:C. 將攻擊用的機器碼寫入堆疊等資料區域,並跳到那裡執行的攻擊

以往的攻擊常利用緩衝區溢位將機器碼寫入堆疊,並讓返回位址指向那裡來執行。CPU的分頁表中有禁止執行的位元(NX位元等),只要作業系統將堆疊、堆積、.data設為禁止執行,並將.text設為禁止寫入,這種方法就行不通了。像JIT編譯器那樣在執行中產生程式碼的情況,則是切換寫入與執行的權限來使用。

常見問題

緩衝區溢位一定會讓程式停止嗎?

不一定。超出的寫入若落在未使用的區域,看起來什麼事都沒發生;若破壞了其他變數,則會在別處產生錯誤的結果。有時要到返回位址被破壞或堆疊保護啟動時,才會異常終止。

使用 strncpy 就安全嗎?

strncpy 最多只複製指定數量的字元,但來源字串較長時不會加上結尾的 '\0',之後的處理可能讀到範圍外。請使用可指定大小且一定會加上結尾的 snprintf,或在 strncpy 之後自己寫入結尾字元。

解析中的「緩衝區溢位」

出現「緩衝區溢位」的題目(3題)

  1. 關於ASLR(位址空間配置隨機化)的目的,下列何者正確?
  2. 藉由不讓記憶體分頁同時具備「可寫入」與「可執行」(W^X,寫入與執行分離),較容易防禦的攻擊為下列何者?
  3. 把8個字元的字串 "ABCDEFGH" 傳給上方的函式 save。會發生的事,下列何者正確?

相關名詞

堆疊 返回位址 ASLR(位址空間配置隨機化) 共享函式庫(Shared library) 頁表 JIT編譯(即時編譯) 變數 巨集(macro) 未定義行為 位元欄位(bit-field)

前往名詞解釋列表