首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

緩衝區溢位攻擊原理深度解析與防禦實戰

     編輯:關於VC++

緩衝區溢位 是歷史最悠久、破壞力最強的軟體弱點類型之一。雖然原理簡單,但現代作業系統與編譯器已內建多重防護機制。本文從堆疊溢位原理、Shellcode 設計、實戰攻擊範例到編譯器防禦 (/GS) 全方位剖析。

什麼是緩衝區溢位?

當資料寫入緩衝區超過其容量,多餘資料會覆蓋相鄰記憶體。依位置分類:

  • 靜態儲存區溢位:全域/靜態變數區
  • 堆疊溢位:函數呼叫框架、區域變數、返回位址 — 攻擊價值最高
  • 堆積溢位:動態配置記憶體

攻擊靶標:存在漏洞的 victim 程式


void GetComputerName(SOCKET sck, LPSTR szComputer) {
    char szBuf[512];
    recv(sck, szBuf, sizeof(szBuf), 0);          // 無長度檢查
    LPSTR szFileName = szBuf;
    while (*szFileName == '\\') szFileName++;    // 略過雙反斜線
    while (*szFileName != '\\' && *szFileName != '\0') {
        *szComputer++ = *szFileName++;           // 複製至 szComputer — 易溢位
    }
    *szComputer = '\0';
}

void ShowComputerName(SOCKET sck) {
    char szComputer[16];                         // 僅 16 字元緩衝區
    GetComputerName(sck, szComputer);            // 傳入未檢查長度
    printf(szComputer);                          // 格式化字串漏洞額外贈送
}

堆疊佈局與攻擊向量分析

ShowComputerName 編譯後堆疊 (stdcall 調用慣例):

高位址
+------------------+  ← 呼叫者堆疊框架
|  參數 sck        |  [esp+4]  (stdcall 由呼叫者清理堆疊,ret 4)
+------------------+
|  返回位址 (RA)   |  [esp]    ← 關鍵目標
+------------------+  ← 進入 ShowComputerName 後
|  舊 EBP          |  [ebp]    (若編譯器啟用框架指標)
+------------------+
|  szComputer[16]  |  [esp]    ← 區域變數區
|  ...             |
+------------------+
低位址 (堆疊向下增長)

關鍵洞察:ret 4 執行後,ESP 指向 szComputer + 24 (返回位址 + 參數 sck 被彈出)。若我們將返回位址覆蓋為 JMP ESP 指令位址,並在 szComputer + 24 放置 Shellcode,控制權即可轉移。

實戰攻擊鏈構建

1. 尋找 JMP ESP (固定位址、無 0x00/0x5C)

  • EXE 基址通常較低,高位元組含 0x00 → 不適合
  • kernel32.dll 基址固定但 XP SP1 無 JMP ESP
  • user32.dll 基址固定 (0x77D4xxxx),搜尋發現 0x77D437DB = JMP ESP

2. Shellcode 設計課題與解法

3. 完整攻擊載荷結構 (STUB)

+------------------+
| Padding 1 (18B)  |  填滿 szComputer[16] + 對齊
+------------------+
| JMP ESP (4B)     |  0x77D437DB 覆蓋返回位址
+------------------+
| Padding 2 (4B)   |  填滿參數 sck 空間
+------------------+
| StubStubCode     |  11 條組語:解碼 StubCode + 跳轉
+------------------+
| StubParam        |  API 位址表 (LoadLibrary, GetProcAddr, VirtualAlloc...)+ DLL/函數名
+------------------+
| StubCode         |  階段二載入器:建立 Socket、下載攻擊主體、重定位、跳轉 AttackerEntry
+------------------+
| Padding 3        |  偽裝成合法 UNC 路徑結尾
+------------------+

4. 核心 StubStubCode (11 條組語)


xor ecx, ecx
mov cx, wXorSize          ; 待解碼資料長度
lea esi, [esp + byXorOffset] ; 待解碼資料起始 (StubParam)
push esi                  ; 傳遞參數給 StubCode
xor_loop:
    mov al, [esi]
    xor al, byXorMask     ; XOR 還原
    mov [esi], al
    inc esi
    loop xor_loop
lea eax, [esp + byEntryOffset] ; StubCode 入口
call eax                  ; 跳轉執行

5. StubCode 功能

  1. 透過 StubParam 中的 LoadLibrary/GetProcAddress 解析 ws2_32.dll Socket API
  2. VirtualAlloc 分配 RWX 記憶體 (存放下載的攻擊主體)
  3. 監聽 TCP 埠 (12345),接受攻擊者連線
  4. 將分配的記憶體基址傳給攻擊者
  5. 接收攻擊者傳送的經重定位 PE 映像
  6. 定位 AttackerEntry (RVA) 並跳轉執行

防禦機制:編譯器 /GS (Buffer Security Check)

Visual Studio .NET 2002+ 引入 /GS 編譯選項:


void ShowComputerName(SOCKET sck) {
    DWORD_PTR cookie = __security_cookie;  // 編譯器插入:啟動時隨機初始化
    char szComputer[16];
    GetComputerName(sck, szComputer);
    printf(szComputer);
    __security_check_cookie(cookie);       // 編譯器插入:返回前驗證
}

__security_check_cookie 邏輯:


void __fastcall __security_check_cookie(DWORD_PTR cookie) {
    if (cookie == __security_cookie) return; // 正常
    report_failure();                        // 溢位偵測 → 終止程式
}
  • Cookie 置於區域變數與返回位址之間,溢位必先覆蓋 Cookie
  • 隨機初始化使攻擊者難以預測/偽造 Cookie
  • 缺點:僅偵測堆疊溢位,無法防禦堆積溢位;偵測後直接終止程式 (DoS)

根本原因與責任歸屬

  • x86 架構:返回位址與資料共用堆疊,且堆疊向下增長 (高位址→低位址),擴大覆蓋範圍
  • C 標準庫:strcpy/gets/sprintf 等不檢查長度的函數為效率犧牲安全
  • 程式設計師:未驗證輸入長度、使用不安全 API

最有效防禦:開發階段嚴格檢查緩衝區邊界、使用安全版本函數 (strcpy_s, StringCchCopy)、啟用 /GS、DEP (NX bit)、ASLR 多層防護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
限制解決方案
不可含 0x00 (字串結束) / 0x5C (反斜線,被略過)XOR 編碼:尋找一個 Key (0-255),使 Shellcode XOR Key 後無禁用字元
Shellcode 過長難以完整放入兩階段載入:StubCode (解碼器) + 階段二 Shellcode (透過 Socket 下載)
無法使用絕對定址全程使用相對定址 (RIP/EIP 相對)