| 函數 | 用途 |
NtQuerySystemInformation | 查詢系統進程/控制代碼資訊 (SystemInformationClass=0x10 控制代碼表) |
RtlCreateQueryDebugBuffer | 建立進程除錯緩衝區 |
RtlQueryProcessDebugInformation | 查詢進程模組載入資訊 (識別 msgina.dll) |
RtlRunDecodeUnicodeString | 解碼 Unicode 字串 (單位元組 XOR 滾動金鑰) |
RtlDestroyQueryDebugBuffer | 釋放除錯緩衝區 |
代碼架構解析 (原文重點函數)
1. 權限提升 AddDebugPrivilege
BOOL AddDebugPrivilege() {
HANDLE hToken; TOKEN_PRIVILEGES tp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
return AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
}
2. 定位 Winlogon PID FindWinLogon
- 呼叫
NtQuerySystemInformation(0x10, ...) 獲取所有控制代碼表
- 篩選
HandleType == 5 (Process 物件)
- 對每進程建立除錯緩衝區,查詢模組清單
- 尋找模組名含 "WINLOGON" 且載入 "MSGINA" (非 "NWGINA") 的進程
3. 記憶體掃描定位憑證
NT 4.0:讀取 PEB (0x7FFDF000) → 進程堆 → 掃描堆區域尋找使用者名/網域
Win2K:VirtualQueryEx 遍歷整個用戶模式位址空間 (0x00010000 ~ 0x7FFEFFFF),檢查 MEM_COMMIT 且非 PAGE_GUARD 的區域,ReadProcessMemory 讀取比對使用者名/網域
4. 解密演算法 RtlRunDecodeUnicodeString
// 簡化邏輯:單位元組 XOR 滾動金鑰
void RtlRunDecodeUnicodeString(BYTE bHash, PUNICODE_STRING pStr) {
WCHAR* pw = pStr->Buffer;
for (ULONG i = 0; i < pStr->Length / sizeof(WCHAR); i++) {
pw[i] ^= bHash;
bHash = (BYTE)(bHash + pw[i]); // 滾動金鑰
}
}
Win2K 因不儲存雜湊位元組,需暴力嘗試 0x00-0xFF,驗證解碼結果是否為可列印 ASCII (0x20-0x7E)。
現代 Windows (Vista/7/8/10/11) 防禦機制
| 機制 | 版本 | 原理 | 對本技術影響 |
| LSA Protection (RunAsPPL) | 8.1+ | LSASS 以 Protected Process Light 執行,拒絕非簽名除錯器附加 | 完全阻擋 OpenProcess(PROCESS_VM_READ) 於 LSASS,但 Winlogon 非 PPL 仍理論可讀 |
| Credential Guard (VBS) | 10 Enterprise+ | 虛擬化隔離 LSASS,憑證存於 VTL 1,Host (VTL 0) 無法讀取 | 徹底杜絕記憶體提取,Winlogon 亦不再持有明文密碼 |
| Restricted Admin Mode | 8.1+ | RDP 限制管理模式,不將明文密碼傳送至目標 | 減少記憶體中明文密碼殘留 |
| SeDebugPrivilege 移除 | 預設策略 | 管理員不再預擁有 SeDebugPrivilege,需透過 GPO 明確授予 | 提高攻擊門檻,需本地提權 |
防禦與偵測建議
- 啟用 Credential Guard (需 TPM 2.0、UEFI、Hyper-V、Enterprise 版)
- 設定 LSA Protection:
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\RunAsPPL = 1
- 限制 SeDebugPrivilege:GPO
Computer Configuration → Windows Settings → Security Settings → Local Policies → User Rights Assignment → Debug programs 僅保留必要服務帳號
- 部署 EDR/AV 記憶體掃描:偵測
OpenProcess(PROCESS_VM_READ) → ReadProcessMemory 針對 winlogon.exe/lsass.exe 的異常序列
- 啟用 Windows Defender Credential Guard 事件日誌:Event ID 4673 (Sensitive Privilege Use)、4688 (Process Creation with SeDebugPrivilege)
- 定期輪換密碼、推行 MFA、使用 Windows Hello for Business / FIDO2 金鑰 取代密碼認證
合法替代方案 (系統管理/開發)
- Windows Hello / FIDO2 / 憑證認證:無密碼認證,根除密碼竊取風險
- 群組受控服務帳號 (gMSA):服務間認證自動輪換密碼
- Remote Credential Guard:RDP 將認證導向本地裝置,遠端不留存
- Just-In-Time (JIT) 提權:Azure AD PIM、CyberArk、BeyondTrust 等 PAM 方案
- DPAPI / Credential Manager API:應用程式安全儲存秘密,而非記憶體明文
結語
本技術展示了 Windows 早期架構為了 SSO 便利性而在記憶體保留可逆加密密碼的設計權衡。現代 Windows 透過虛擬化隔離 (VBS)、保護進程 (PPL)、預設最小權限等纵深防禦,已大幅提高憑證竊取難度。安全從業者應專注於防禦部署、偵測規則、無密碼架構遷移,而非攻擊技術本身。
- 上一篇文章: 打造自訂 Windows 終端服務客戶端:整合 Microsoft Terminal Services ActiveX 控制項 (C++ Builder)
- 下一篇文章: Shell.Application自動化控制Windows Shell操作
Copyright ©
程式碼之家 All Rights Reserved