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

字符串比較陷阱:棧溢出導致的密碼驗證繞過漏洞分析

     編輯:關於C語言

問題現象

編寫一個密碼驗證程式:輸入字符串與預設密碼 "1234567" 比較,相符輸出 congratulations!,否則輸出 try again!。實測發現,輸入某些 8 位字符串(如 33333333)也會誤判為「恭喜通過」。

代碼還原

#include <stdio.h>
#include <string.h>

#define PASSWORD "1234567"

void cmp(char* str);

int main() {
    char buf[1024];
    printf("please input password:\n");
    scanf("%s", buf);
    cmp(buf);
    return 0;
}

void cmp(char* str) {
    int ret;          // 定義在 buf 之前
    char buf[8];      // 僅 8 字節
    ret = strcmp(str, PASSWORD);
    strcpy(buf, str); // 冗餘語句:當 str 長度 > 7 時發生棧溢出
    if (ret == 0)
        printf("congratulations!\n");
    else
        printf("try again!\n");
}

根因深度剖析

什麼是棧溢出?

棧溢出屬於緩衝區溢出的一種。函數運行時在棧上分配局部變量空間;若向緩衝區寫入超過其容量的數據,多餘數據會覆蓋相鄰的棧變量甚至返回地址,導致程式行為不可預測。

本例中的內存佈局與破壞過程

  • 棧上變量佈局(由高地址向低地址增長):ret (4 字節) → buf[8] (8 字節)。
  • strcpy(buf, str) 將輸入字符串從 buf[0] 開始寫入。若輸入長度 ≥ 8,多餘字節會向高地址溢出,覆蓋 ret 的低位字節。
  • ret = strcmp(...) 的返回值:相等為 0 (0x00000000);str > PASSWORD 為正數(如 1 → 0x00000001);str < PASSWORD 為負數(如 -1 → 0xFFFFFFFF)。

漏洞觸發條件

輸入與密碼關係ret 原始值溢出後首字節ret 實際值程式輸出
str == PASSWORD0 (0x00000000)0x000congratulations! ✓
str > PASSWORD1 (0x00000001)被輸入字符覆蓋為 0x33 ('3')0x33000000 ≠ 0try again! ✓
str < PASSWORD-1 (0xFFFFFFFF)被覆蓋為 0x330x33FFFFFF ≠ 0try again! ✓
str > PASSWORD 且第 8 字符為 '\0'1 (0x00000001)0x000congratulations! ✗ 誤判

輸入 33333333(8 字符,無結束符)時,strcpy 會把 8 個 '3' 寫入 buf,第 9 字節隱含的 \0 剛好覆蓋 ret 的最低字節,使 ret 從 1 變為 0,繞過驗證。

修復方案

  1. 刪除冗餘語句:strcpy(buf, str) 本無業務意義,直接移除。
  2. 調整變量定義順序:將 ret 置於 buf 之後,即使發生溢出也不會踩踏關鍵變量( defence-in-depth )。
  3. 使用安全函數:改用 strncpy 或 snprintf 限制拷貝長度。
  4. 編譯器防護:開啟 -fstack-protector (GCC) 或 /GS (MSVC) 啟用棧金絲雀檢測。

修正後代碼

void cmp(char* str) {
    char buf[8];      // 先定義緩衝區
    int ret;          // 再定義返回值
    ret = strcmp(str, PASSWORD);
    // 移除 strcpy
    if (ret == 0)
        printf("congratulations!\n");
    else
        printf("try again!\n");
}

總結

這是一個經典的「看似無害的冗餘代碼引發安全漏洞」案例。它警示我們:

  • 任何未做長度檢查的拷貝操作都是潛在隱患。
  • 局部變量佈局順序影響溢出後果,關鍵變量應盡量遠離緩衝區。
  • 代碼審計時要關注「業務邏輯無關」的語句,它們往往是漏洞溫床。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved