iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Security

CTF 菜鳥修練日誌系列 第 26 篇

Day 26:【Pwn】什麼是緩衝區溢位 (Buffer Overflow)?記憶體結構解

  • 分享至 

  • xImage
  •  

1. 前言與 Pwn 領域簡介

在 CTF 競賽中,Pwn 這個詞源自駭客俚語「Pwned」(意指完全掌控、攻陷系統)。Pwn 專注於挖掘與利用二進位程式中的記憶體安全漏洞(Memory Corruption Vulnerabilities),最終目標通常是奪取目標主機的 Shell 權限並讀取 Flag。

在眾多漏洞類型中,最經典、歷史最悠久也最基礎的莫過於 緩衝區溢位 (Buffer Overflow, BOF)。要理解 BOF,我們必須先看懂程式在電腦記憶體中的長相。


2. 程式的記憶體配置 (Memory Layout)

當一個 C 語言程式被載入作業系統執行時,作業系統會在記憶體中為它分配一塊連續的空間,其經典的虛擬記憶體佈局(由低位址到高位址)如下:

  1. Text (Code) 區段:存放編譯後的機器碼(Machine Instructions),通常具備唯讀屬性。
  2. Data / BSS 區段:存放全域變數 (Global Variables) 與靜態變數。
  3. Heap (堆積):由低位址向高位址生長,用於動態記憶體分配(如 malloc 或 new)。
  4. Stack (堆疊):由高位址向低位址生長,用於存放區域變數 (Local Variables)、函數參數與返回地址 (Return Address, EIP/RIP)。

3. 核心原理:什麼是緩衝區溢位?

Stack(堆疊) 的運作機制是後進先出 (LIFO)。當進入一個函數時,系統會在堆疊上開闢一個空間(Stack Frame)給區域變數。

如果程式在接收使用者輸入(例如使用不安全的函數如 strcpy, gets, 或未限制長度的 scanf)時,沒有檢查輸入的長度,當輸入的資料大小超過原本配置的緩衝區 (Buffer) 大小:

  • 多出來的資料不會被擋掉,而是會繼續往記憶體的高位址「溢出」。
  • 溢出的資料會覆蓋掉相鄰的區域變數、Saved Frame Pointer (SBP),甚至是 函數的返回地址 (Return Address)。
  • 當函數執行結束準備返回 (ret) 時,CPU 會把被篡改的返回地址當成下一個執行指令的位址跳過去——這就是劫持程式控制流 (Control Flow Hijacking) 的由來!

4. 實戰演練:撰寫一個存在漏洞的 C 程式

我們在 WSL 中親自寫一個存在經典緩衝區溢位漏洞的 C 程式,並觀察其崩潰 (Segmentation Fault) 現象。

步驟一:撰寫 Vulnerable C 程式

在 WSL 終端機中執行以下命令:

# 1. 建立具有漏洞的 C 原始碼
cat << 'EOF' > bof_demo.c
#include <stdio.h>
#include <string.h>

void vulnerable_function() {
    char buffer[16]; // 僅分配 16 bytes 的緩衝區
    
    printf("Enter your input: ");
    gets(buffer);    // 極度危險的函數,不檢查輸入長度!
    
    printf("You entered: %s\n", buffer);
}

int main() {
    printf("=== Buffer Overflow Demo ===\n");
    vulnerable_function();
    printf("Program finished normally.\n");
    return 0;
}
EOF

# 2. 編譯 C 程式 (關閉部分防護以便觀察溢位,如 Stack Canary 與棧不可執行)
gcc -fno-stack-protector -z execstack bof_demo.c -o bof_demo

https://ithelp.ithome.com.tw/upload/images/20261010/20184211gcU1DbUFUj.png

步驟二:測試正常輸入與溢位崩潰

我們分別用「正常長度」與「超長字串」來執行剛才編譯好的二進位檔:

# 測試 1:正常輸入 (小於 16 bytes)
./bof_demo
# 輸入:Hello

https://ithelp.ithome.com.tw/upload/images/20261010/20184211IKr5j9TdGD.png

輸出結果:程式正常結束。

# 測試 2:超長輸入(引發緩衝區溢位)
python3 -c "print('A' * 40)" | ./bof_demo

輸出結果:你會發現終端機印出 Segmentation fault (core dumped)!這代表輸入的 40 個 'A' 成功撐爆了 16 bytes 的緩衝區,並一路向上覆蓋了返回地址,導致 CPU 試圖跳去執行記憶體位址 0x41414141('A' 的 ASCII 十六進位)而當機。
https://ithelp.ithome.com.tw/upload/images/20261010/20184211hWO9zDXAgh.png

5. 總結與防禦機制預告

今天我們透過手動寫出漏洞程式並用長字串灌爆堆疊,親眼見證了 Segmentation Fault 的誕生。這正是 Pwn 攻擊中最核心的「覆蓋返回地址」原理。

不過現代作業系統為了防止這類攻擊,內建了許多強大的防禦機制:

  1. Stack Canary (棧保護):在返回地址前放一個隨機金鑰,若被覆蓋會直接終止程式。
  2. NX / DEP (No-Execute):禁止在堆疊上執行惡意 shellcode。
  3. ASLR (位址空間配置隨機化):讓每次程式執行時的記憶體位址都隨機變動。

上一篇
Day 25:【Reverse】神器 Ghidra 初體驗:C/C++ 執行檔的反組譯與 Decompile
下一篇
Day 27:【Pwn】格式化字串漏洞 (Format String Bug) 原理與實作
系列文
CTF 菜鳥修練日誌 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言