Buffer Overflow Definition

  • known as a buffer overrun or buffer overwrite
  • A condition at an interface under which more input can be placed into a buffer or data holding area than the capacity allocated, overwriting other information. Attackers exploit such a condition to crash a system or to insert specially crafted code that allows them to gain control of the system.

Buffer overflow basics

  • Programming error
    • process 試圖將資料儲存到超過限制大小的 buffer 之外的位置
    • 覆寫相鄰的記憶體位置 (可能存放其他程式的變數與參數)
  • Buffer 可能在 process 的 stack, heap, data section
  • 後果:
    • 程式資料被破壞
    • 非預期的控制權轉移
    • 記憶體存取違規
    • 執行由攻擊者選擇的程式碼

Example

  • str2 覆寫到 str1 的記憶體位置,導致比對錯誤

Attacker

  • Needs for the Attacker: 利用 Buffer Overflow
  • 在某個程式中識別出一個 buffer overflow 的漏洞
    • 可以透過外部來源的資料觸發,而這些資料是由攻擊者所控制的
  • 了解該 buffer 在 process memory 中是如何被儲存的
    • 以及其破壞相鄰記憶體位置的可能性
    • 可能改變程式的執行流程

如何辨識具有漏洞的程式:

  • 檢查程式原始碼
  • 追蹤程式在處理超大輸入時的執行過程
  • 使用工具自動辨識可能存在漏洞的程式
    • fuzzing: 一種軟體測試技術
      • 使用隨機產生的資料作為程式輸入
      • 輸入的範圍可以非常大
      • 用來測試程式是否能正確處理所有這些異常輸入

Programs

Basic machine level

  • 所有由機器指令所操作的資料,都儲存在處理器 registers 或記憶體中
  • 資料的解釋方式: 完全由指令的功能所決定
  • 可以被視為整數值、資料的位址、字元陣列等
  • 組合語言程式設計師的責任: 確保任何儲存的資料值都被正確地解讀

Assembly language programs

  • 擁有對系統資源最大的存取權限
  • 但也需要最高的開發成本與程式設計責任

Modern high-level programming languages

ex: Java, Python

  • 具有強型別與合法操作的概念
  • 不容易受到 buffer overflow 攻擊: flexibility and safety
    • 不允許儲存超出限制的資料
  • 代價是資源使用增加 (在編譯期與執行期都會加入檢查)
  • 限制了程式撰寫的靈活性

Between these two extremes

ex: C and related languages

  • 具有許多現代高階語言的控制結構與資料型別抽象
  • 但仍允許直接存取低階系統資源
    • 容易受到 buffer overflow 攻擊
    • 存在大量歷史悠久、被廣泛使用但不安全,因此容易有漏洞的程式碼

Stack overflows

  • 也被稱為 stack smashing
  • 當被攻擊的 buffer 位於 stack 上時所發生的情況
  • Stack frame 儲存的資料:
    • Return address to the calling function (Old frame pointer)
    • Parameters passed to the called function
    • Values of local variables

Example

  • 覆寫到 Return addressOld frame pointer

More Vulnerabilities

  • Potential for a buffer overflow: 存在於任何將資料複製 (copied) 或合併 (merged) 到 buffer 的地方
  • 當程式沒有檢查以確認 buffer 是否足夠大,或被複製的資料是否被正確結束時,就會發生
    • 有些資料是從程式外部讀入的
    • 同一個程式內不同函數之間的不安全資料複製
  • 常見的不安全 C 標準函式庫函數:
    • 若未檢查正在傳輸資料的總大小,就不應該使用
    • gets, sprintf, strcat, strcpy, vsprintf

Shellcode

  • 由攻擊者提供的程式碼
    • 通常儲存在 overflow 的 buffer 中
    • 傳統上會將控制權轉移到使用者的 shell (命令列直譯器)
  • 本質上就是 machine code (機器碼)
    • 與特定的處理器架構與作業系統相關
    • 傳統上需要良好的組合語言能力才能撰寫
  • 已經有許多網站與工具被開發出來,用以自動化這個過程

Example

某個入侵者已經以 normal user 的身分取得某系統的存取權限,並希望利用一個受信任工具中的 buffer overflow 漏洞,以取得更高的權限

  • 使用 debugger 執行程式,分析以確定相關資訊
    • 被攻擊目標 buffer 在 stack 上可能的位置
    • 需要多少資料才能到達並覆蓋 old frame pointerreturn address
  • 假設已取得以下資訊
    • How many bytes are needed to fill the buffer and reach the saved frame pointer?

Defending against buffer overflows

Compile-time defenses

強化新開發的程式,使其能抵抗攻擊

Choice of programming languages

  • 使用現代的高階程式語言
  • 優點: 不容易受到 buffer overflow 攻擊
    • 具有強型別概念以及允許的操作限制
    • 編譯器會加入額外程式碼,以強制執行範圍檢查與合法操作
  • 缺點:
    • 必須在執行時額外執行檢查程式碼
    • 彈性與安全性需要以資源使用成本作為代價
      • 由於處理器效能快速提升,這種成本變得不那麼重要
    • 會失去對某些低階指令與硬體資源的存取能力

Safe coding techniques

  • C 語言的設計者更重視空間效率與效能,而不是型別安全性
    • 假設程式設計師在撰寫程式時會謹慎行事
  • 程式設計師需要檢查程式碼,並重寫任何不安全的寫法
  • 程式碼不僅是為了正常且成功的執行
    • 而是要持續意識到事情可能會如何出錯
    • Graceful failure: 當發生意料之外的情況時,總是能做出合理的處理

Language extensions and use of safe libraries

  • 處理 dynamically allocated memory 時會有更大的問題
    • 因為在編譯時無法得知記憶體大小資訊
  • 需要語言擴充與函式庫 (library routines) 的支援
    • 缺點:
      • 通常會有效能上的損失
      • 程式與函式庫需要使用修改過的編譯器重新編譯
      • 對新的作業系統可行,但對第三方應用程式可能會造成問題
  • C 語言的常見問題: 使用不安全的標準函式庫函數
    • 以較安全的替代版本取代它們
    • ex: Libsafe
      • 加入額外檢查,確保複製操作不會超出 stack frame 的範圍
      • 動態函式庫: 不需要重新編譯現有程式

Stack protection mechanisms

  • 在函式進入與離開時加入額外程式碼,用來檢查 stack 是否有被破壞
    • Stackguard: 最知名的保護機制之一,是一種 GCC 編譯器擴充
    • Function entry code: 在 old frame pointer 位址下方寫入一個 canary value (金絲雀值)
    • Function exit code: 檢查 canary value 是否改變
    • canary value: 不可預測且在不同系統上不同
      • 避免被一起覆蓋成偽造數值
    • 缺點:
      • 所有需要保護的程式都必須重新編譯
      • stack frame 結構被改變: 會造成一些程式 (例如 debugger) 出現問題
  • 其他變種: StackshieldReturn Address Defender (RAD)
    • 也是 GCC 擴充: 加入額外的函式進入與離開檢查程式碼
    • 不會改變 stack frame 的結構
    • Function entry code: 將 return address 複製到一個安全的記憶體區域
    • Function exit code: 檢查 stack frame 中的 return address 是否與安全區域中的備份一致
    • 與未修改的 debugger 相容
      • 不會改變 stack frame 的結構
    • 程式必須重新編譯

Run-time defenses

在現有程式執行時偵測並中止攻擊

  • 可以透過 OS updates 來部署,以提供保護
    • 通常需要重新編譯現有程式
    • 通常會涉及記憶體管理機制的改變

Executable Address Space Protection

  • 阻止在 stack 上執行程式碼
  • 將 virtual memory 的 pages 標記為不可執行 (nonexecutable)
    • 需要記憶體管理單元 (MMU) 的支援
    • 已成為現代作業系統的標準功能
  • 缺點:
    • 無法支援需要在 stack 上執行程式碼的情況
    • ex: Java Runtime system, nested functions in C, Linux signal handlers

Address space randomization

  • 改變關鍵資料結構的位置
    • Stack, heap, global data
    • 對每個 process 使用 random shift
    • 現代系統的位址空間很大: 浪費一部分空間的影響可以忽略不計
  • 隨機化 heap buffer 的位置
  • 標準函式庫函數的位置也會隨機化

Guard pages

  • 在記憶體中的關鍵區域之間放置 guard pages
    • 在記憶體管理單元 (MMU) 中被標記為非法位址
    • 任何對這些位址的存取都會導致 process 中止
  • 擴展: 在 stack frames 與 heap buffers 之間也放置 guard pages

Other forms of overflow attacks

  • Replacement stack frame
  • Return to system call
  • Heap overflows
  • Global data area overflows
  • Other types of overflows

Heap Overflow

  • 攻擊的 buffer 位於 heap
    • 通常位於 program code 之上
    • 記憶體是由程式動態請求,用於動態資料結構
      • ex: linked lists
  • 沒有 return address
    • 沒有簡單的方法可以進行控制流轉移
    • 但可能存在可以被利用的 function pointer
    • 或者操控記憶體管理相關的資料結構
  • Defenses:
    • 讓 heap 變成不可執行 (non-executable)
    • 隨機化 heap 上的記憶體配置方式
  • next = malloc(sizeof(chunk_t)); 在 heap

Global Data Overflow

  • 攻擊的 buffer 位於 global data
    • 可能位於 program code 之上
    • 如果該區域同時包含 function pointer 與易受攻擊的 buffer
    • 或者鄰近 process management tables
    • 目標是覆蓋 function pointer,使其在之後被呼叫時執行攻擊者指定的程式碼
  • Defenses:
    • 將 global data region 設為不可執行,或隨機化其位置
    • 移動 function pointers,或使用 guard pages
  • struct chunk {...} chunk; 屬於 global data

紅字整理

P37: Stack Protection Mechanisms, The canary value: unpredictable and different on different systems, Why?

  • 避免被一起覆蓋成偽造數值

P38: Stack Protection Mechanisms, Compatible with unmodified debuggers, Why?

  • 不會改變 stack frame 的結構