首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

緩衝區溢出攻擊原理深度解析:從棧帖結構到 DEP/ASLR 防禦機制

     編輯:程式設計疑難解答

核心機制:函數調用棧帖結構與局部變量溢出

1. 標準棧帖佈局 (x86, `__stdcall` 約定)

高地址
+------------------+
| 函數參數 (右到左壓棧) |  <- 調用者壓入
+------------------+
| 返回地址 (EIP)      |  <- CALL 指令壓入,RET 彈出跳轉
+------------------+
| 老 EBP (基址指針)   |  <- 函數序言: PUSH EBP; MOV EBP, ESP
+------------------+
| 局部變量            |  <- 分配棧空間: SUB ESP, size
| ...                |
| 寄存器保存區        |  <- 可選,編譯器決定
+------------------+
低地址 (棧增長方向)
ESP 指向棧頂

2. 溢出攻擊步驟

  1. 輸入超長數據:程序使用不安全函數 (`strcpy`、`gets`、`sprintf` 等) 複製用戶輸入到固定大小局部緩衝區,無長度檢查。
  2. 覆蓋關鍵數據:數據溢出向高地址擴展,依次覆蓋:
    • 其他局部變量
    • 保存的寄存器
    • 老 EBP
    • 返回地址 (EIP) ← 關鍵目標
  3. 控制執行流:函數結束執行 `RET` 指令,彈出被篡改的返回地址跳轉,CPU 執行攻擊者指定地址代碼。
  4. 執行 Shellcode:攻擊者在輸入數據中嵌入機器碼,並將返回地址指向緩衝區地址 (或 `jmp esp` 指令地址),獲取 Shell 權限。

經典攻擊鏈

1. 溢出覆蓋返回地址
2. 跳轉到緩衝區 Shellcode (需可執行棧)
   或
2. ROP (Return-Oriented Programming): 跳轉到現有代碼片段 (Gadgets) 組合邏輯
   如: POP RET; MOV EAX, ...; INT 0x80 等
3. 調用 system("/bin/sh") 或 VirtualProtect 修改內存屬性
4. 反彈 Shell / 執行任意命令
5. 提權 (本地提權漏洞) -> 獲取 Root/SYSTEM
6. 橫向移動 / 持久化 / 數據竊取

現代防禦機制演進

技術原理繞過難度備註
Stack Canary (GS/SSP)函數序言在局部變量與老 EBP 間放隨機 Canary 值,結尾檢查是否被改。改了則終止程序。高需泄露 Canary 值或利用非棧溢出漏洞
DEP / NX (Data Execution Prevention)標記棧/堆/數據段為「不可執行」 (CPU NX 位)。Shellcode 注入棧無法直接執行。中繞過: ROP 鏈調用 `VirtualProtect`/`mprotect` 修改內存屬性,或跳轉到已可執行模塊 (無 ASLR 時)。
ASLR (Address Space Layout Randomization)程序加載基址、堆、棧、共享庫基址隨機化。攻擊者無法預知 `system`、`VirtualProtect`、Gadgets 地址。高繞過: 信息洩露漏洞泄露基址、部分覆蓋 (低字節)、JIT 噴射、側信道攻擊。
CFI (Control Flow Integrity)編譯器插桩,間接跳轉/調用/返回前驗證目標地址合法性 (如 Microsoft CET, Clang CFI)。極高硬件輔助 (Intel CET: Shadow Stack, IBT) 大幅提升門檻。
SafeSEH / SEHOP保護異常處理鏈不被劫持。高Windows 特有。

編譯器/開發層面最佳實踐

  • 禁用不安全函數:`strcpy`→`strcpy_s`/`strncpy`、`gets`→`fgets`、`sprintf`→`snprintf`/`vsnprintf`。
  • 啟用編譯器保護:MSVC `/GS` (默認開)、GCC `-fstack-protector-strong -D_FORTIFY_SOURCE=2`、Clang 同。
  • 靜態分析:Coverity、SonarQube、Cppcheck 掃描緩衝區溢出隱患。
  • 模糊測試:AFL、LibFuzzer 自動發現輸入處理漏洞。
  • 使用安全語言/庫:Rust、Go、C++ `std::string`/`std::vector`/`span` 避免裸指針操作。

總結

棧溢出本質是內存安全邊界檢查缺失導致控制數據 (返回地址) 被數據覆蓋。現代防禦構建了多層纏繞防線:Canary 守門 → DEP 禁執行 → ASLR 盲打 → CFI 鎖定控制流。開發者應從源頭消除不安全 API,啟用編譯器強化,配合 SDLC 安全流程,將漏洞擠壓到極小面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved