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

Windows 服務安全性兩大隱憂:互動式服務風險與 _alloca 堆疊溢位

     編輯:VC 教學

議題一:互動式服務的安全邊界破壞

背景

Windows 服務通常在背景以 LocalSystem 高權限運行,無使用者介面。若服務需與登入使用者互動,微軟早期提供「允許服務與桌面互動」選項 (登錄 Type & 0x0100 或 CreateService SERVICE_INTERACTIVE_PROCESS),讓服務開啟互動式桌面視窗。

核心風險

  • 桌面即安全邊界:互動式桌面上任何視窗皆可互相傳送訊息,不受建立者安全內容限制。
  • 惡意訊息攻擊:一般使用者程式可向服務視窗發送偽造訊息 (WM_COMMAND、WM_TIMER 等),竄改服務行為、提權或導致崩潰。
  • 未來將移除支援:微軟已宣告後續 Windows 版本將完全移除互動式服務支援。

檢測清單:你的服務是否處於風險中?

若程式碼含以下特徵,立即重構:

  • 以 LocalSystem 執行且標記「允許與桌面互動」
  • 呼叫 OpenWindowStation/GetThreadDesktop 取得互動式桌面
  • 使用 MessageBox 且 uType 包含 MB_SERVICE_NOTIFICATION 以外旗標
  • 呼叫 OpenDesktop("winsta0", ...) 建立 UI
  • 在 OpenDesktop 取得的桌面上 LoadLibrary/GetProcAddress

正確替代方案

  1. Client/Server 架構:服務作為 Server,透過 RPC、Named Pipe、Socket、COM** 提供介面,前端 GUI 作為 Client 呼叫。
  2. 簡易狀態通知:僅需顯示訊息時,使用 MessageBox(..., MB_SERVICE_NOTIFICATION) (僅限 NT 4.0 SP3+)。

議題二:_alloca 堆疊溢位拒絕服務攻擊

危險範例


void func(char* szData) {
    PVOID p = _alloca(lstrlen(szData)); // 攻擊者傳入超大字串 → 堆疊耗盡 → 例外 → 程式終止
    // use p
}

若在服務程式中,將導致服務掛掉,造成嚴重拒絕服務。

正確防護模式:結構化例外處理 (SEH) + _resetstkoflw


void func(char* szData) {
    __try {
        PVOID p = _alloca(lstrlen(szData));
        // use p
    }
    __except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        _resetstkoflw(); // 重置堆疊狀態,避免後續 Guard Page 失效
    }
}

延伸風險:ATL 字串轉換巨集

A2W、W2A、CW2CT 等巨集內部使用 _alloca。服務端程式碼嚴禁直接用於不可信輸入長度的字串。必須先驗證長度上限,或改用堆積配置 (new/malloc) 的安全轉換函式。

附錄:緩衝區重複使用導致明文洩漏 (經典競態條件)

加密流程若「同一緩衝區先存明文、再加密、再發送」,多執行緒下可能發生指令重排:

正常:載入明文 → 加密 → 發送密文
競態:載入明文 → 發送(明文!) → 加密

此錯誤曾存在於 IIS 4.0 SSL 實作,極罕見負載下洩漏一封明文封包。修正:嚴格分離明文緩衝區與密文緩衝區,發送前確認密文緩衝區已填充。

思考題:下列程式碼有何缺陷?


void ShuffleAndUpdate(char* szName, char* szPwd, DWORD index, DWORD d) {
    DWORD dwArray[32]; ZeroMemory(dwArray, sizeof(dwArray));
    BOOL fAllowAccess = FALSE;
    if (IsValidUser(szName, szPwd)) {
        fAllowAccess = TRUE;
        ShuffleArray(dwArray, szName);
    }
    dwArray[index] = d;               // 潛在索引越界 (index >= 32)
    if (fAllowAccess) { /* 敏感操作 */ }
}

答案: 1) index 未驗證邊界,導致緩衝區溢位。2) ShuffleArray 若修改 dwArray 大小/邏輯,後續 dwArray[index] 更不可預期。3) 敏感操作應在驗證通過且所有輸入經過完整性檢查後才執行。

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