破解 NTLM 密碼:深入 SAM 結構的內幕

TeamT5 「ThreatVision 威脅情資平台」榮獲 Computex Best Choice Award 金獎服務MDR

威脅偵測應變代管服務

IR

資安事件應變處理服務

產品ThreatSonar Anti-Ransomware

威脅鑑識分析與回應平台

ThreatSonar

威脅鑑識分析平台

ThreatVision

威脅情資平台

深暗網威脅情資

ThreatVision 最新威脅情資類別

產業方案金融機構

醫療院所

科技製造業

政府機關

關於 TeamT5TeamT5 團隊

人才招募

最新消息部落格聯絡我們聯絡我們

合作夥伴

TW

技術分析SubscribeRSS破解 NTLM 密碼:深入 SAM 結構的內幕2024.08.13IR TeamShare: By Sharon不知道大家有沒有好奇過,像 mimikatz 和 impacket 這樣的工具是如何取出使用者的 NTLM 雜湊密碼 (NTLM Hash / NTHash)呢?若是想理解為什麼,我們就得深入從 windows registry 了解 SAM(安全帳戶管理器)結構。首先,Windows 作業系統會將使用者的 NTLM 雜湊密碼 (NTHash) 透過 RC4 或是 AES「加密」演算後存放到 Registry 的 SAM 中,這當中會使用到包括其他 windows 的預設字串以及預設的加密演算法,如下所示:Windows 的 預設字串:!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%0123456789012345678901234567890123456789NTPASSWORD0x00 x 2Windows 預設加密演算法:DES → 用來當作第一層使用者密碼的混淆MD5 → 用來製作鑰匙

微軟為了增加密碼安全性,會把上述加密後的資訊分散存放到以下四個註冊值:User F : \HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\%RID%\FUser V : \HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\%RID%\VAccount F : \HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\FSystem : \HKEY_LOCAL_MACHINE\\System\CurrentControlSet\Control\Lsa

fig 1. User F / V

fig 2. Domain Account F

接下來,我們將以「RC4 的加密方式」為例,一步一步剖析,如何透過擷取上述 Registry 個別的特定參數,說明解密的原理。單元會依照此順序做介紹:User F 值User V 值Domain Account F 值SYSTEM 結構整理以上取得的資訊梳理加解密過程1.User F值(fixed length, 80)\HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\%RID%\F

在這三個結構裡,User F 值 應該是最直覺的。他的大小永遠固定為 0x00 到 0x4F,也就是 80 bytes 的大小。

那在解密的過程中,我們 User F 值 唯一需要用到的資訊是「UserId」的值。

這裡所標示的 UserId 相同於我們的「相對識別碼 (RID)」。

RC4 加解密時會需要用到 RID 的值 (F4 01 00 00) 做為計算鑰匙的一部分。

DES 加解密時 RID 會被用來計算成 K1 與 K2 這兩把鑰匙。RC4_Encrypted (最終結果會存入 User V[14])= RC4( DES_Encrypted, MD5(SYSKEY+DWORD(RID) +"NTPASSWORD"+"\x00"))DES_Encrypted= DES(NTHash, k1) + DES(NTHash, k2)所以接下來,我們將從使用者 F 獲取的 RID ,跟著下面的步驟計算出我們 K1 和 K2 的值:RID DWORD (4 位元組 / 4 bytes) 格式=F4 01 00 00。K1 和 K2 各是 7 位元組 (byte),製作方式就是單純將 F4 01 00 00 依照順序先填滿 K1 再來接續填滿 K2。如下圖:所以我們現在的結果如下:K1 = F4 01 00 00 F4 01 00K2 = 00 F4 01 00 00 F4 01把 K1 和 K2 先轉換成二位元 (F4 = 1111010)

把 K1 和 K2 從 7 位元組 (byte) 轉為 8 位元組,我們要先把所有位元組以連接在一起的方式列出來,然後在每 7 位元 (bit) 的分段開來後面 + 0,進行同位位元的計算。K1 同位元計算連接在一起呈現: 11110100000000010000000000000000111101000000000100000000每 7 位元 (bit) 分段後 "+ 0" :1111010+0=F40000000+0=000100000+0=400000000+0=000000111+0=0E1010000+0=A00000010+0=040000000+0=00K2 同位元計算連接在一起呈現: 00000000111101000000000100000000000000001111010000000001每 7 位元 (bit) 分段後 "+ 0" :0000000+0=000111101+0=7A0000000+0=000010000+0=200000000+0=000000011+0=061101000+0=D00000001+0=02所以我們現在得到的結果如下: > - K1 = F4 00 40 00 0E A0 04 00> - K2 = 00 7A 00 20 00 06 D0 02User F 的重點整理User F 裡唯一取得的資訊為 RID。

此參數在 DES 會被用來運算成 K1 與 K2 的兩把鑰匙,也會被 RC4 作為製作密鑰運算中的一環。RID = F4 01 00 00K1 = F4 00 40 00 0E A0 04 00K2 = 00 7A 00 20 00 06 D0 02User F 取出的值與加密過程的對應:1.DES_Encrypted= DES(NTHash, k1)+DES(NTHash, k2)2.SYSKEY= RC4(EncKey, MD5((Salt + "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"+"\x00"+Bootkey+"0123456789012345678901234567890123456789"+`"\x00"))3.RC4_Encrypted (最終結果會存入 User V[14])= RC4(DES_Encrypted, MD5(SYSKEY+DWORD(RID)+"NTPASSWORD"+"\x00"))2.User V 值(varies in length, 80)\HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\%RID%\V

User V 的第一部分:「SAMP_VARIABLE_LENGTH_ATTRIBUTE」有固定大小為: 0xCC (0~0xCB), 也就是 204 bytes 的大小。它儲存了 UserV 值 中前 17 個陣列 (array) 的資訊摘要,包含自己。每個陣列長度為 12 位元組 (4+4+4)*17=0xCC ,而把這陣列切成 4 位元組的三等份,從左到右分別記載著「偏移量(Offset)」、「長度(Length)」以及「限定符(Qualifier)」,如下:資料的起點應計算為: 偏移量 + 0xCC → 所以 0xCC 是資料的開頭資料的終點則計算為: 偏移量 + 0xCC + 長度 → 而 0x1C0 是資料的結尾如果想開發工具的話,理解此結構可以幫助我們辨別 UserV 值 內的資訊是否存在,若 Length 為 0 ,即為不存在。那為了解密,我們需要取的是 UserV 值 中的第 13 (LMHash) 和第 14 (NTHash) 的陣列。請看下列圖例:

RC4 加密的 NTHash(開頭 "User V 值圖例" 的 NTHash (SAMP_User_UNICODE_PWD) 使用的第二層加密為 AES,而非 RC4。所以請參考此 NTHash 為準)以上兩者都屬於加密使用者密碼的方式,而自從 Windows Vista 和 Windows Server 2008 之後,微軟預設就禁止了 LMHash。所以這篇文章會以 NTHash 來做解密的運算。SAMP_USER_UNICODE_PWD (User V[14]) = 01 00 01 00 92 A7 A7 EC 28 9E 26 60 DD F4 8F 54 C9 2D 3F 87User V 的重點整理User V 裡唯一取得的資訊是「最終加密版本的 NTHash」 (User V[14]) = RC4(RC4(DES(NTHash)))User V[14]

= SAMP_USER_UNICODE_PWD

= 01 00 01 00 92 A7 A7 EC 28 9E 26 60 DD F4 8F 54 C9 2D 3F 87User V 取出的值與加密過程的對應:DES_Encrypted= DES(NTHash, k1) + DES(NTHash, k2)SYSKEY= RC4(EncKey, MD5((Salt+"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"+"\x00"+Bootkey+"0123456789012345678901234567890123456789"+"\x00"))RC4_Encrypted (最終結果會存入 User V[14])= RC4(DES_Encrypted, MD5(SYSKEY+DWORD(RID)+"NTPASSWORD"+"\x00"))3.Domain Account F 值(RC4 version)(fixed length, 336)\HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\FDomain Account F 值 的結構在加密方法上會有所不同,上面所呈現的是使用 RC4 加密的結構示意圖。

先前提到加密會使用 RC4 與 AES 兩種方式,區分方法是看「Version」的值,如圖:

而加密結構上的不同也只出於 0x68 後的資訊(如下圖所示)。

了解兩者加密運算法的話,便能得知後面結構的不同僅來自加密過程會用到的數值不同而已 (RC4 的 0x70, 0x80, 0x90 接固定為 16 bytes)。Domain Account F 的重點整理Domain Account F 裡取得的資訊為下:加密方式: 0x10002 → RC4加密/解密的資訊: Salt = 0x70= 6F D9 76 B6 45 84 57 CB 9D 12 33 47 23 11 AC 9FEncKey = 0x80 = 2C E6 69 B6 BD FB A6 D0 F7 2F 42 9F 6F 1A F2 08Domain Account F 取出的值與加密過程的對應:DES_Encrypted*=DES(NTHash, k1) + DES(NTHash, k2)SYSKEY=RC4(EncKey, MD5((Salt+"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"+"\x00"+Bootkey+"0123456789012345678901234567890123456789"+"\x00"))RC4_Encrypted (最終結果會存入 User V[14])=RC4(DES_Encrypted, MD5(SYSKEY+DWORD(RID)+"NTPASSWORD"+"\x00"))4.SYSTEM 結構\HKEY_LOCAL_MACHINE\\System\CurrentControlSet\Control\Lsa\{Data, GBG, JD, Skew1}使用 Registry Viewer (切記 windows 內建的 registry editor )

Windows 登入的本機帳號及密碼,會以 LM 或 NTLM hash 的型態存放在 SAM 登錄檔 (Registry 的 User V[14]) 裡。而自從 Windows NT 4.0 後,預設就開始使用 Syskey 來加密 SAM 裡面的資訊。這把 Syskey 會被做以下會講到的運算,分開來存入 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa 的四個機碼: "JD, Skew1, GBG, Data" 。真正數值可到機碼的 Class name 存取出來 (可參考以下圖)。所以自從 SAM 的密碼開始被加密後,要解出密碼就需要連登錄檔的 SYSTEM 也一併取回才能解出 SysKey ,才有辦法解開使用者密碼的 Hash 值。"JD, Skew1, GBG, Data" 這四個地方取得出 Class Name (字串值) 的資訊可以組成「bootkey(也稱 Syskey)」,這把鑰匙是 Windows 系統用來加密和保護系統關鍵數據的一部分。例圖:

製作 bootkey 過程:把四個值連接在一起:

假設 JD, Skew1, GBG, 和 Data 這四個值如下,將十六進制序列依序連接在一起,形成一個長的十六進制數字串。 合併數據: JD + Skew1 + GBG + Data

= "c2 a4 4d fa" + "a2 30 c4 ab" + "74 e4 48 2e" + "73 0b d8 57"

= c2 a4 4d fa a2 30 c4 ab 74 e4 48 2e 73 0b d8 57最終得出 c2 a4 4d fa a2 30 c4 ab 74 e4 48 2e 73 0b d8 57

使用 ShiftArray 陣列演算法,將值進行重新排列,生成 bootkey。ShiftKey 典型值

= [0x8, 0x5, 0x4, 0x2, 0xB, 0x9, 0xD, 0x3, 0xC, 0x0, 0x6, 0x1, 0xA, 0xE, 0xF, 0x7]對應字節排序下來將是我們的 Bootkey。

SYSTEM 的重點整理這裡取得的唯一資訊為:Bootkey = 74 30 a2 4d 2e e4 0b fa 73 c2 c4 a4 48 d8 57 abSYSTEM 取出的值與加密過程的對應:1.DES_Encrypted= DES(NTHash, k1) + DES(NTHash, k2)2.SYSKEY=RC4(EncKey, MD5((Salt + "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"+"\x00"+Bootkey+"0123456789012345678901234567890123456789"+"\x00"))3.RC4_Encrypted (最終結果會存入 User V[14])= RC4(DES_Encrypted, MD5(SYSKEY+DWORD(RID)+"NTPASSWORD"`+`"\x00"))5.整理以上取得的資訊Windows 會用到的預設字串:!@#$%^&()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(@&%0123456789012345678901234567890123456789NTPASSWORD0x00 x 2

User FRID = F4 01 00 00K1 = F4 00 40 00 0E A0 04 00K2 = 00 7A 00 20 00 06 D0 02

User VSAMP_USER_UNICODE_PWD= User V[14]= 01 00 01 00 92 A7 A7 EC 28 9E 26 60 DD F4 8F 54 C9 2D 3F 87

Domain Account F加密方式 = RC4加密/解密的 資訊:Salt = 0x70 = 6F D9 76 B6 45 84 57 CB 9D 12 33 47 23 11 AC 9FEncKey = 0x80 = 2C E6 69 B6 BD FB A6 D0 F7 2F 42 9F 6F 1A F2 08SystemBootkey =74 30 a2 4d 2e e4 0b fa 73 c2 c4 a4 48 d8 57 ab6.梳理加解密過程根據上述的「加密」過程,我們來對比一下「解密」的過程:加密過程DES_Encrypted=DES(NTHash, k1)+DES(NTHash, k2)SYSKEY=RC4(EncKey, MD5((Salt + "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"+"\x00"+Bootkey+"0123456789012345678901234567890123456789"+"x00"))RC4_Encrypted (最終結果會存入 User V[14])=RC4(DES_Encrypted, MD5(SYSKEY+DWORD(RID)+"NTPASSWORD"+"\x00"))DES_EncryptedDES 的運算目的是給予 NTHash 第二層的加密保護,而使用 RID 作為 DES 中的 K1 和 K2 用意在於當兩個或多個使用者擁有相同密碼時可以進一步的混淆使用者的 NTHash。SYSKEYSYSKEY 會進行第一次的 RC4 加密運算,把 User F 值 的 EncKey(0x80) 作為 Data 加密起來。加密會使用到上述 User F 值 的 Salt (0x70) 、 Bootkey 、Windows 加密預設字串。RC4_Encrypted最後,我們將 SYSKEY 算出來的數字做為鑰匙,把 DES 加密後的 NTHash 作為 Data 再次進行 RC4 加密的動作。解密過程 (含圖例)SYSKEY=RC4(EncKey, MD5((Salt + "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"+"\x00"+Bootkey+"0123456789012345678901234567890123456789"+"\x00"))RC4_Decrypted=RC4(User V[14], MD5(SYSKEY+DWORD(RID)+"NTPASSWORD"+"\x00"))DES_Decrypted= DES(RC4_Decrypted, k1)+DES(RC4_Decrypted, k2)SYSKEY解密過程的話,我們需要先從所有加密的「鑰匙」開始運算,第一步先拿最外層的鑰匙 SYSKEY 作解密。步驟跟上面的一樣,因為 RC4 是對稱式加密 (symmetric encryption)。RC4_Decrypted有了 SYSKEY 即可運算出下一把鑰匙: MD5(SYSKEY + RID +NTPASSWORD + 0x00)。拿取User V 值 的 第 14 個陣列 (SAMP_USER_UNICODE_PWD or User V[14]) 作為 Data ,使用鑰匙進行 RC4 的解密。DES_Decrypted現在我們剩下的就是被 DES 加密起來的 NTHash (DES(NTHash)),因 DES 也是對稱式的加密,用 K1 與 K2 重複相同的動作即可解出使用者的 NTHash。

(cover source: pexels)2024.08.13IR TeamShare: 立即訂閱我們的電子報,獲得資安新知與技術文章立即訂閱

*按下此訂閱按鈕,即表示您同意杜浦數位安全的隱私權政策,並同意收到我們寄送的資訊

服務MDRIR產品ThreatSonar Anti-RansomwareThreatSonarThreatVision深暗網威脅情資產業方案金融機構醫療院所科技製造業政府機關關於 TeamT5TeamT5 團隊人才招募最新消息部落格聯絡我們聯絡我們合作夥伴媒體專區TeamT5 CSIRTCERTIFICATION隱私權與Cookies使用政策服務條款資訊安全政策© 2025 TeamT5, Inc. All Rights Reserved.TW

為提供您最佳的服務體驗,本網站使用 Cookies。當您使用本網站,即表示您同意 Cookies 技術支援。更多資訊請參閱隱私權與Cookies使用政策。我同意

随便看看