Windows SAM文件与NTLM Hash解密原理及攻防实战

📅 2026/8/6 5:56:49
Windows SAM文件与NTLM Hash解密原理及攻防实战
1. 项目概述从SAM文件到NTLM Hash的攻防实战在Windows安全领域本地用户凭证的存储与保护机制一直是攻防双方博弈的核心战场。每当提及Windows密码破解两个名字总是绕不开一个是存储在注册表HKEY_LOCAL_MACHINE\SAM中的安全账户管理器Security Accounts Manager数据库另一个则是大名鼎鼎的NTLMNT LAN Manager哈希。你可能听说过使用mimikatz或impacket等工具可以轻松“抓取”哈希但你是否真正理解当你执行sekurlsa::logonpasswords或reg save hklm\sam sam.hive这些命令时系统底层究竟发生了什么Windows是如何将你的明文密码转换成一串看似随机的十六进制字符并层层加密后存入那个神秘的SAM文件中的更重要的是攻击者又是如何逆向这个过程最终拿到可用于横向移动或密码破解的NTLM Hash的这篇文章我将从一个实战研究者的角度带你彻底拆解Windows 10环境下从SAM文件提取到最终解密出NTLM Hash的完整链条。我们不仅会复现攻击者常用的技术路径更会深入其背后的密码学原理和Windows安全子系统设计逻辑。理解这些对于构建有效的防御策略、进行安全的渗透测试演练乃至深入操作系统安全机制都至关重要。无论你是安全工程师、系统管理员还是对底层安全感兴趣的技术爱好者这篇近万字的深度剖析都将为你提供一套清晰的“地图”和“工具”。2. SAM文件与NTLM Hash的核心原理剖析要理解如何解密必须先彻底搞清楚Windows是如何加密存储密码的。这个过程远非简单的“密码-哈希-存储”那么简单它是一个涉及多层加密、密钥派生和特定数据结构的复杂工程。2.1 NTLM Hash密码的“数字指纹”首先我们必须区分“NTLM Hash”和“NTLM响应”。这里我们讨论的是前者即用户密码的哈希值它是整个认证链条的源头。当你在Windows中设置或更改密码时系统并不会存储你的明文密码。取而代之的是它会使用MD4消息摘要算法对你的密码转换为Unicode编码进行计算生成一个128位16字节的哈希值这就是NTLM Hash也称为NTHash。例如假设你的密码是Password123。系统会将字符串Password123转换为UTF-16LE编码即每个字符占2字节小端序。对这个Unicode字节序列进行MD4哈希运算。输出一个16字节的哈希值看起来像这样8846F7EAEE8FB117AD06BDD830B7586C。这个哈希值就是你的密码在系统中的“代表”。在早期的NTLMv1认证中服务器端验证的就是这个值。但问题在于如果攻击者直接获取到这个哈希他就可以在不破解明文密码的情况下使用“哈希传递”Pass-the-Hash攻击直接模拟你的身份登录其他系统。因此Windows绝不会让这个哈希“裸奔”在磁盘上。2.2 SAM文件的结构一个加密的凭证保险库SAM文件本质上是Windows注册表HKEY_LOCAL_MACHINE\SAM子树在磁盘上的持久化存储通常是%SystemRoot%\System32\config\SAM。在系统运行时这个子树被加载到注册表中并受到SYSTEM权限的严格保护普通用户和进程无法直接访问。SAM中存储了本地用户以及工作组模式下的计算机的账户信息核心是经过加密的凭证哈希。它的结构可以理解为一系列预定义格式的二进制记录。对于我们解密NTLM Hash最关键的是两个部分F值和V值它们位于每个用户的注册表路径下例如HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\000001F4\其中000001F4是管理员账户的RID。F值固定长度数据块这是一个80字节的固定长度二进制数据。它包含了一些账户的元数据但对我们解密过程最关键的是一个4字节的相对标识符RID。RID是用户账户的唯一数字标识如Administrator是500普通用户从1000开始。在后续的解密计算中这个RID将作为密钥派生的一部分确保即使两个用户密码相同其在SAM中的密文也不同这增加了暴力破解的难度。V值可变长度数据块这是一个可变长度的二进制数据其结构更为复杂。它包含了一个头部SAMP_VARIABLE_LENGTH_ATTRIBUTE固定204字节和紧随其后的多个属性列表。每个属性由12字节的“描述头”包含偏移量、长度和限定符和实际的数据体组成。我们梦寐以求的、经过加密的NTLM Hash就存储在V值中一个特定的属性里通常通过其限定符来标识例如NTHash对应的属性。关键点V值中的数据并不是直接存储NTLM Hash而是存储了经过SYSKEY和用户RID等因子加密后的密文。SYSKEY是Windows引入的一个额外保护层。2.3 SYSKEY系统密钥的引入与作用从Windows NT 4.0 Service Pack 3开始微软引入了SYSKEY系统密钥来进一步加密SAM数据库中的哈希值。SYSKEY是一个128位的密钥它的引入旨在防止攻击者直接复制SAM文件并离线破解。SYSKEY本身并不直接存储在SAM文件中而是被拆分并混淆后存储在注册表的另一个位置HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa下的几个特定值中通常涉及JD、Skew1、GBG、Data等。这些值看起来是随机的二进制数据需要按照特定的算法如一个固定的置换表进行重组和变换才能还原出原始的128位SYSKEY也常被称为BootKey。为什么需要SYSKEY想象一下如果没有SYSKEY攻击者只需获得SAM文件就可以针对每个用户的哈希独立进行离线暴力破解。而有了SYSKEY后攻击者必须同时获得SYSTEM注册表配置单元因为其中包含还原SYSKEY所需的数据和SAM文件才能开始解密过程。这相当于给整个凭证保险库加了一把共用的“主锁”你必须先打开主锁才能去尝试打开里面每个用户的小保险箱。2.4 加密链条的完整视图现在我们可以勾勒出从用户密码到最终存储在SAM中密文的完整加密链条生成NTLM HashNTHash MD4(UTF-16-LE(Password))第一层加密DES使用从用户RID派生出的两个7字节密钥K1 K2对16字节的NTLM Hash进行DES加密。具体操作是将NTLM Hash的前8字节用K1加密后8字节用K2加密然后将两个8字节的DES密文拼接起来得到一个16字节的DES_Encrypted数据块。这一步的目的是引入用户特异性RID使得相同密码在不同用户下的密文不同。生成SYSKEY从SYSTEM注册表配置单元的特定值中通过解码和置换算法计算出128位的BootKey即SYSKEY。第二层加密RC4这是最核心的一步。系统使用一个复杂的密钥派生函数生成一个用于RC4流加密的密钥。这个派生过程大致如下输入包括从SAM的F值中取得的Salt和EncKey这两个值也存储在用户数据中、上一步得到的BootKey、以及两个硬编码的字符串常量常被称为F值常量串和G值常量串内容类似!#$%^*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*%和0123456789012345678901234567890123456789。将这些数据按特定顺序拼接计算其MD5哈希值。这个128位的MD5哈希结果就是用于加密的RC4密钥。最终存储使用上一步生成的RC4密钥对DES_Encrypted数据块进行加密得到的RC4_Encrypted密文最终被写入到用户V值的特定属性中如SAMP_USER_UNICODE_PWD。至此你的密码经过MD4哈希、DES加密、RC4加密并与系统唯一的SYSKEY绑定后才安然躺在了SAM文件中。攻击者若想逆向此过程必须步步为营。3. 实战环境搭建与关键文件获取理论足够扎实后我们进入实战环节。首先需要一个可控的Windows 10环境。强烈建议在虚拟机如VMware或VirtualBox中进行所有操作避免对宿主机造成任何风险。3.1 实验环境准备我使用的是Windows 10 22H2专业版并创建了一个测试用户testuser密码设置为一个复杂密码以便观察。你需要管理员权限来执行后续的所有操作。操作心得在虚拟机中操作时可以方便地创建快照。在进行任何可能影响系统的操作如修改注册表权限前务必创建一个快照以便随时回滚。3.2 获取SAM与SYSTEM文件由于系统运行时SAM和SYSTEM注册表配置单元被独占锁定我们无法直接复制。通常有两种方法获取它们方法一利用注册表保存功能推荐这是最常用且相对安全的方法。以管理员身份打开命令提示符CMD或PowerShell执行以下命令reg save hklm\sam C:\sam.save reg save hklm\system C:\system.save这两个命令会将HKEY_LOCAL_MACHINE\SAM和HKEY_LOCAL_MACHINE\SYSTEM子树的内容保存到指定的文件sam.save和system.save中。这些文件包含了我们解密所需的所有原始数据。方法二从磁盘镜像或卷影副本中提取在离线取证场景下攻击者可能通过访问C:\Windows\System32\config\目录下的SAM和SYSTEM文件以及可能需要的SECURITY文件来获取它们。在系统运行时这些文件被锁定但可以通过加载另一个操作系统的磁盘如Linux Live CD或利用卷影副本服务VSS来访问。例如可以使用vssadmin命令创建卷影副本然后从中复制文件。重要安全警告获取到的sam.save和system.save文件包含了可用于解密本地所有用户哈希的关键信息。务必妥善保管仅在隔离的、无网络连接的分析环境中使用分析完毕后应立即彻底删除。切勿将这些文件泄露或存储在联网的机器上。3.3 初步探查文件内容拿到文件后我们可以使用一些工具进行初步查看以验证文件有效性并熟悉结构。虽然直接解析二进制结构比较困难但我们可以用impacket套件中的secretsdump.py脚本进行快速验证这实际上已经是在解密了但我们先只看它能否识别。首先确保你的分析机通常是Linux或安装了Python的Windows上安装了impacket。然后执行python3 secretsdump.py -sam sam.save -system system.save LOCAL如果一切正常你会看到脚本开始解析并尝试解密最终输出本地用户的用户名、RID和对应的LM/NTLM哈希如果存在。如果看到类似testuser:1001:aad3b435b51404eeaad3b435b51404ee:8846F7EAEE8FB117AD06BDD830B7586C:::的输出那么恭喜你已经成功了一半。最后那串8846...就是testuser的NTLM Hash。但我们的目标不是简单地使用工具而是理解工具背后的每一步。所以让我们暂时放下secretsdump从底层开始。4. 手动解密流程拆解与实现现在我们将扮演“解密者”手动还原从SAM/SYSTEM文件到NTLM Hash的每一步。这个过程需要一些编程能力推荐使用Python和对二进制数据的操作。4.1 步骤一解析SYSTEM文件还原BootKeySYSTEM文件的核心价值在于还原SYSKEYBootKey。我们需要从其中提取JDSkew1GBGData这几个值。这些值并不直接以明文形式存在而是隐藏在注册表值的“类名”Class Name数据中。操作流程解析SYSTEM文件SYSTEM文件是一个注册表配置单元Registry Hive。我们可以使用Python的regipy库或者更底层的struct模块来解析。我们需要定位到路径\ControlSet001\Control\Lsa注意ControlSet001可能因系统而异通常是当前控制集。提取特定值找到该路径下的JDSkew1GBGData这四个值。它们的类型通常是REG_BINARY二进制数据。每个值的数据长度应该是16字节128位。将它们按JD、Skew1、GBG、Data的顺序拼接起来得到一个64字节的原始数据。应用置换表ShiftArrayWindows使用一个固定的16字节置换表来混淆BootKey。这个表是[0x8, 0x5, 0x4, 0x2, 0xB, 0x9, 0xD, 0x3, 0xC, 0x0, 0x6, 0x1, 0xA, 0xE, 0xF, 0x7]。它的意思是最终BootKey的第0个字节取自原始拼接数据第0x8索引处的字节第1个字节取自原始数据第0x5索引处的字节依此类推。得到BootKey应用完整个置换表后得到的16字节数据就是真正的BootKey。Python代码片段示例import struct # 假设我们已经从SYSTEM hive中读取到了jd_bytes skew1_bytes gbg_bytes data_bytes 各16字节 raw_bytes jd_bytes skew1_bytes gbg_bytes data_bytes # 64字节 shift_array [0x8 0x5 0x4 0x2 0xB 0x9 0xD 0x3 0xC 0x0 0x6 0x1 0xA 0xE 0xF 0x7] bootkey b for i in shift_array: bootkey raw_bytes[i].to_bytes(1 little) # 注意字节序通常是小端序 print(fBootKey: {bootkey.hex()})4.2 步骤二解析SAM文件提取用户数据接下来解析SAM文件定位到目标用户例如RID为0x3E8十进制1000的普通用户的F和V值。操作流程定位用户节点在SAM Hive中路径是\SAM\Domains\Account\Users。其下有许多以RID命名的子键十六进制如000001F4000003E8。读取F值进入目标RID的子键读取F值类型为REG_BINARY。这是一个80字节的二进制数据。我们需要从中提取出RID和用于DES加密的Salt与EncKey。RID通常位于F值数据块的特定偏移量例如偏移0x30处是一个4字节的小端序整数。000001F4就是十进制的500。Salt和EncKey在F值中Salt有时称为F值中的加密盐和EncKey加密密钥材料也位于固定的偏移位置。它们的长度通常各为16字节。你需要参考SAM结构文档或逆向工程结果来精确定位。在一些资料中Salt对应F值中偏移0x70开始的16字节EncKey对应偏移0x80开始的16字节。读取V值同样在该用户子键下读取V值。这是一个可变长度的二进制数据。我们需要解析其内部的属性列表。解析V值属性V值的前204字节是固定头部。之后是一个接一个的属性。每个属性以12字节的头开始结构为偏移量4字节、长度4字节、限定符4字节。实际属性数据存储在V值数据起始地址 0xCC204 偏移量的位置长度为长度字节。定位加密的NTLM Hash我们需要找到限定符Qualifier为特定值的属性。对于NTLM Hash这个限定符通常是0x1420或与SAMP_USER_UNICODE_PWD相关的标识。找到后该属性数据体就是经过RC4_Encrypted的密文我们记为encrypted_hash。解析心得V值的解析是最容易出错的一步因为其结构紧凑偏移量计算必须精确。建议编写代码时先以十六进制编辑器如010 Editor或HxD手动查看一个已知的SAM导出文件对照文档确认各个字段的位置和含义再用代码实现自动化解析。4.3 步骤三执行逆向解密计算现在我们拥有了所有“拼图”BootKey来自SYSTEM用户RIDSalt和EncKey来自用户F值encrypted_hash来自用户V值两个硬编码的常量字符串F常量串和G常量串。解密是加密的逆过程我们按相反顺序操作计算SYSKEY解密用构造字符串Salt F_Constant_String b\x00 BootKey G_Constant_String b\x00。这里的是字节拼接。计算这个拼接后字节串的MD5哈希值得到16字节的md5_digest。使用RC4算法以md5_digest为密钥对EncKey来自F值进行解密。注意RC4是对称算法加密和解密是同一个操作。这一步的结果称为SYSKEY或称为FinalKey的一部分。SYSKEY RC4(md5_digest EncKey)。计算用于解密用户哈希的RC4密钥构造字符串SYSKEY RID4字节小端序 bNTPASSWORD b\x00。计算这个字符串的MD5哈希值得到16字节的user_rc4_key。第一层RC4解密使用上一步得到的user_rc4_key作为RC4密钥对从V值中提取的encrypted_hash进行RC4解密。des_encrypted_data RC4(user_rc4_key encrypted_hash)。此时得到的是DES_Encrypted数据块16字节。从RID派生DES密钥K1 K2这是一个特定的密钥转换过程。将4字节的RID小端序扩展为两个7字节的密钥。以RID 0xF4 0x01 0x00 0x00 (500)为例将RID字节重复填充RID_Bytes [0xF4 0x01 0x00 0x00]K1_raw RID_Bytes RID_Bytes[0:3]-[0xF4 0x01 0x00 0x00 0xF4 0x01 0x00](7字节)K2_raw RID_Bytes[1:] RID_Bytes-[0x01 0x00 0x00 0xF4 0x01 0x00 0x00](7字节)将7字节的原始密钥转换为8字节的DES密钥。DES密钥是56位有效位8位奇偶校验位。转换算法是将7字节展开成56位的位串然后在每7位后插入一个奇偶校验位通常为0组成8字节。这个过程有标准算法在Python中可以使用Crypto.Util.strxor或手动实现。第二层DES解密将上一步得到的16字节des_encrypted_data分成前后8字节。使用DES算法以K1为密钥解密前8字节。使用DES算法以K2为密钥解密后8字节。将两个8字节的解密结果拼接起来NTLM_Hash DES_decrypt(K1 first_8_bytes) DES_decrypt(K2 second_8_bytes)。至此你应该得到了一个16字节32个十六进制字符的数据这就是该用户的NTLM Hash。代码实现注意事项确保所有数据的字节序Endianness正确Windows通常是小端序Little-Endian。RC4和DES算法的实现要准确。可以使用成熟的密码学库如Python的Crypto.Cipher中的ARC4和DES模块。硬编码的常量字符串必须完全准确包括大小写和特殊字符。整个过程中最脆弱的环节是数据结构解析。一个字节的偏移错误就会导致后续所有计算失败。务必使用已知的正确SAM/SYSTEM文件进行测试和调试。5. 自动化工具解析与高级利用场景理解了手动解密原理后我们再回过头来看自动化工具。它们封装了上述所有复杂步骤让我们能专注于利用。5.1 经典工具链使用与原理对应impacket-secretsdump这是impacket套件中的王牌工具。我们之前已经用过它的基本功能。它的强大之处在于不仅能处理本地SAM/SYSTEM还能通过DCSync攻击从域控制器提取域哈希或通过WMI、SMB等方式远程提取。对应原理它内部实现了我们上面描述的所有解析和计算步骤。当你运行secretsdump.py -sam sam.save -system system.save LOCAL时它就是在执行步骤4.1到4.3。高级用法-ntds参数指定NTDS.dit文件Active Directory数据库-system指定SYSTEM引导键可以导出域内所有用户哈希。-hashes参数支持传递哈希进行身份验证PtH。mimikatz这款工具功能更为强大和直接主要在内存中操作。lsadump::sam此命令需要SYSTEM权限。它直接读取本机注册表中的SAM和BOOTKEY对应我们的SYSTEM在内存中解密并显示哈希。这相当于跳过了文件导出步骤直接在内核层面执行了我们的解密流程。sekurlsa::logonpasswords这是另一个维度。它并非从SAM文件解密而是从LSASS本地安全机构子系统服务进程的内存中提取当前已登录用户的明文密码、哈希和票据。这利用了Windows将凭证缓存在内存中以支持单点登录的特性。防御此类攻击需要启用Credential Guard等缓解措施。John the Ripper / Hashcat获取到NTLM Hash后这两个是进行离线破解的终极武器。它们本身不参与从SAM中提取哈希而是对提取出的哈希进行暴力破解或字典攻击。格式NTLM Hash在John中的格式是NT在Hashcat中是mode 1000。命令示例# John the Ripper john --formatnt hash.txt --wordlistrockyou.txt # Hashcat hashcat -m 1000 hash.txt rockyou.txt5.2 NTLM Hash的利用方式获取NTLM Hash不是终点而是新攻击面的起点。哈希传递Pass-the-Hash PtH这是最直接、最危险的利用方式。攻击者无需知道明文密码直接使用NTLM Hash通过网络认证如SMB RDP WMI等。许多工具原生支持此功能。impacket套件几乎全系支持-hashes LMHASH:NTHASH参数。CrackMapExeccrackmapexec smb 192.168.1.0/24 -u administrator -H NTLM_Hash --local-auth可以在内网中进行快速的哈希传递扫描。防御启用NTLMv2并强制签名、使用Kerberos认证、启用受限管理模式Restricted Admin Mode对于RDP、实施网络分段和强访问控制。离线破解使用John或Hashcat对哈希进行暴力或字典攻击试图还原明文密码。成功率取决于密码强度。彩虹表对于较短的、未加盐的哈希如NTLM彩虹表攻击非常有效。但现代复杂密码能有效抵抗。规则破解结合字典和智能规则如大小写变换、添加数字后缀等可以大幅提升破解常见弱密码的效率。白银票据Silver Ticket攻击在域环境中如果获取了服务账户如MSSQLSvcHTTP等的NTLM Hash实际上是该账户的RC4-HMAC密钥可以伪造服务票据TGS直接访问特定服务而无需与域控制器KDC交互。这种攻击检测困难因为票据是有效的。工具mimikatz的kerberos::golden模块可以伪造白银票据。防御定期轮换服务账户密码、启用高级审计监控Kerberos事件、使用组托管服务账户gMSA。5.3 针对现代Windows的挑战与变化随着Windows安全性的演进传统的SAM解密方法面临新的挑战LSA保护RunAsPPL此功能将LSASS进程作为受保护的进程运行阻止像mimikatz这样的非授权工具读取其内存。可以从注册表或组策略启用。绕过需要更高的权限如加载驱动或利用漏洞。Credential Guard这是基于虚拟化的安全VBS功能将密钥和凭证隔离在安全的、基于虚拟化的容器中LSAIso进程。启用后传统的sekurlsa::logonpasswords将无法提取哈希因为哈希不再存储在常规的LSASS内存中。攻击Credential Guard需要利用Hyper-V或安全内核中的漏洞门槛极高。Windows Hello for Business / Azure AD Join在现代设备管理和混合身份场景下用户凭证可能存储在云中或受TPM保护的硬件设备中本地SAM中可能只存储了缓存的哈希或根本不存储进一步增加了攻击难度。这些防御措施使得直接获取NTLM Hash变得越来越困难推动攻击技术向其他方向如令牌窃取、无文件攻击、供应链攻击发展也迫使防御者必须采用多层次的安全策略。6. 防御策略与安全加固建议知己知彼百战不殆。理解了攻击原理我们才能构建有效的防御。特权账户管理禁用本地管理员为所有工作站和服务器启用本地管理员账户禁用策略或随机化其密码使用LAPS工具。避免域管理员登录普通主机域管理员账户仅限在域控制器和专属管理工作站上使用。实施最小权限原则用户和服务的权限应刚好满足其工作需要不多不少。凭证保护启用Credential Guard对于Windows 10/11 Enterprise和Server 2016这是防御内存中凭证窃取的最强手段。启用LSA保护作为Credential Guard的补充或替代当硬件不支持时。限制WDigest缓存确保注册表项HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest下的UseLogonCredential设置为0以防止明文密码缓存在内存中。启用受限制的管理模式对于RDP连接可以防止凭证被缓存在目标主机上。攻击面减少禁用NTLMv1强制使用NTLMv2或更好的Kerberos。启用SMB签名防止中间人攻击和哈希传递攻击的某些变体。网络分段与防火墙限制关键服务器如域控制器的访问来源仅允许必要的管理流量。禁用不必要的服务如LLMNR、NetBIOS等这些协议可能被用于网络欺骗和哈希中继攻击。监控与检测监控SAM/SYSTEM文件访问通过Sysmon或Windows安全审计策略记录对reg.exe save命令或直接访问C:\Windows\System32\config\SAM文件的异常事件。监控LSASS进程访问使用Sysmon事件ID 10 ProcessAccess或高级安全审计策略监控非系统进程对LSASS的PROCESS_VM_READ访问尝试这是mimikatz等工具的典型行为。监控哈希传递活动在域控制器上启用详细的Kerberos和NTLM认证日志分析异常登录模式如单一账户从多个不同IP快速登录。部署端点检测与响应现代EDR解决方案能够检测凭证转储、哈希传递和无文件攻击等恶意行为。应急响应一旦怀疑哈希已泄露应立即重置相关用户尤其是高权限账户的密码。检查系统中是否存在异常账户、计划任务、服务或进程。使用klist purge命令清除当前会话的Kerberos票据或重启主机。安全是一个持续的过程而非一劳永逸的状态。通过深入理解像SAM解密这样的底层攻击技术我们可以更有针对性地配置安全策略、部署监控措施和制定应急响应计划从而在攻防对抗中占据更有利的位置。