在windows下通过SAMInside提取到的密码Hash时,可以看到有两条,分别是LM-Hash和NTLM-HASH
这是对同一个密码的两种不同的加密方式,下面对其生成原理做个实验。
实验环境:windows server 2003
使用工具:SAMinside
测试服务器密码为123456
0011000 0
1001100 0
1000110 0
0110011 0
0100001 0
1010100 0
1101100 0
0000000 0
此时的密码字符串为0011000010011000100011000110011001000010101010001101100000000000将以上步骤得到的两组16进制字符串,分别作为DES加密key为魔术字符串KGS!@#$%
进行加密
将两组DES加密后的编码拼接得到LM-HASH,计算结果与SAMinside提取结果相同
44EFCE164AB921CAAAD3B435B51404EE
python实现LM-HASH脚本
# coding=utf-8
import base64
import binascii
from pyDes import *
def DesEncrypt(str, Des_Key):
k = des(Des_Key, ECB, pad=None)
EncryptStr = k.encrypt(str)
return binascii.b2a_hex(EncryptStr)
def Zero_padding(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__":
test_str = "123456"
# 用户的密码转换为大写,并转换为16进制字符串
test_str = test_str.upper().encode('hex')
str_len = len(test_str)
# 密码不足14字节将会用0来补全
if str_len < 28:
test_str = test_str.ljust(28, '0')
# 固定长度的密码被分成两个7byte部分
t_1 = test_str[0:len(test_str) / 2]
t_2 = test_str[len(test_str) / 2:]
# 每部分转换成比特流,并且长度位56bit,长度不足使用0在左边补齐长度
t_1 = bin(int(t_1, 16)).lstrip('0b').rjust(56, '0')
t_2 = bin(int(t_2, 16)).lstrip('0b').rjust(56, '0')
# 再分7bit为一组末尾加0,组成新的编码
t_1 = Zero_padding(t_1)
t_2 = Zero_padding(t_2)
print t_1
t_1 = hex(int(t_1, 2))
t_2 = hex(int(t_2, 2))
t_1 = t_1[2:].rstrip('L')
t_2 = t_2[2:].rstrip('L')
if '0' == t_2:
t_2 = "0000000000000000"
t_1 = binascii.a2b_hex(t_1)
t_2 = binascii.a2b_hex(t_2)
# 上步骤得到的8byte二组,分别作为DES key为"KGS!@#$%"进行加密。
LM_1 = DesEncrypt("KGS!@#$%", t_1)
LM_2 = DesEncrypt("KGS!@#$%", t_2)
# 将二组DES加密后的编码拼接,得到最终LM HASH值。
LM = LM_1 + LM_2
print LM
鉴权协议如下的鉴权协议又被称作挑战--认证模式,使用明文口令模式时,网络上传输的就是明文口令本身,这很容易被Sniffer捕获。
挑战/响应模式在传输信道是可被侦听Sniffer,但不可被篡改的情况下,这是一种简单而安全的方法。
LAN Manager Challenge/Response 验证机制,简称LM。该方案比NTLM响应时间更早,安全性更低。
SMB通信,Client A访问Server B通过LM身份验证的过程
首先我们假设Server B的密码为 "WELCOME" , Server B已经缓存了密码的LM-HASH (原始密码在任何情况下都不能被缓存)
我们通过上面的脚本计算"WELCOME"的LM-HASH为 "c23413a8a1e7665faad3b435b51404ee"
Server B -- 8bytes Challenge --> Client A
Server B向Client A发送了一个8字节挑战"0001020304050607"
Client A会根据自己的访问Server B的密码明文计算并缓存密码的LM-HASH(Client A缓存输入密码的哈希值,原始密码会被丢弃,“原始密码在任何情况下都不能被缓存”,这是一条基本的安全准则)
然后在LM-HASH后5个0x00变成 "c23413a8a1e7665faad3b435b51404ee0000000000" ,变为21字节,然后划分成三组,每组7字节
| C23413A8A1E766 | 5FAAD3B435B514 | 04EE0000000000 |
| C21A04748A0E9CCC | 5ED4B47642ACD428 | 0476800000000000 |
C21A04748A0E9CCC ---- 对0001020304050607进行标准DES加密 --> CA1200723C41D577
5ED4B47642ACD428 ---- 对0001020304050607进行标准DES加密 --> AB18C764C6DEF34F
0476800000000000 ---- 对0001020304050607进行标准DES加密 --> A61BFA0671EA5FC8
Client A最终获得一个24字节响应应"CA1200723C41D577AB18C764C6DEF34FA61BFA0671EA5FC8"(这个结果被称为response)
IBM设计的LM Hash算法存在几个弱点,微软在保持向后兼容性的同时提出了自己的挑战响应机制,NTLM Hash便应运而生。
NTLM-HASH计算如下
密码为123456,首先将密码字符串转化为ASCII字符串,ASCII字符串再转换为十六进制字符串,十六进制字符串再转化为Unicode字符串,然后对Unicode字符串使用MD4消息摘要算法,这会产生一个16字节的值, NTLM-HASH
计算结果与SAMinside提取结果相同
32ed87bdb5fdc5e9cba88547376818d4
NTLM验证是一种Challenge/Response
验证机制,由三种消息组成:通常称为类型1(协商),类型2(质询)和类型3(身份验证)。
它基本上是这样工作的:
协商消息从客户端发送到服务器以启动NTLM身份验证。其主要目的是通过FLAG指明支持的选项来建立认证的“基本规则”。
十六进制协商消息:
4e544c4d53535000010000000732000006000600330000000b000b0028000000050093080000000f574f524b53544154494f4e444f4d41494e
将其分解如下:
wireshark 抓包分析协商消息数据包:
质询消息由服务器发送到客户端以响应客户端的协商消息。它用于完成与客户的选择的谈判,并且向客户提供挑战。它可以选择包含有关认证目标的信息。
十六进制质询消息:
4e544c4d53535000020000000c000c003000000001028100
0123456789abcdef0000000000000000620062003c000000
44004f004d00410049004e0002000c0044004f004d004100
49004e0001000c0053004500520056004500520004001400
64006f006d00610069006e002e0063006f006d0003002200
7300650072007600650072002e0064006f006d0061006900
6e002e0063006f006d0000000000
将其分解为其组成字段给出:
wireshark 抓包分析协商消息数据包:
身份验证消息
是身份验证的最后一步。该消息包含客户端对上一步挑战的响应,这表明客户知道账户密码而不直接发送密码。
身份验证消息
还指示身份验证目标(域或服务器名称)和身份验证帐户的用户名以及客户端工作站名称。
身份验证消息结构
客户端创建一个或多个挑战的响应,有六种类型的回应:
wireshark 抓包分析身份验证消息数据包:
NTLM响应由较新的客户端发送。该方案解决了LM响应中的一些缺陷; 然而,它仍然被认为相当薄弱。
此外,NTLM响应几乎总是与LM响应一起发送。该算法的弱点可以用来获取不区分大小写的密码,以及用于查找NTLM响应使用的区分大小写密码的试错法。
客户端计算密码字符串的NTLM哈希。
将16字节的NTLM散列填充为21个字节,
该值分成三个7字节。
这些值用于创建三个DES密钥(每个7字节的作为一个密钥)。
这每一个密钥用于对来自质询消息的挑战进行DES加密(产生三个8字节密文值)。
这三个密文值被连接在一起形成一个24字节的值。这是NTLM的回应。
请注意:只有散列值的计算与LM方案不同; 响应的计算方式是相同的。
例子(一个使用密码“ SecREt01 ” 的用户,质询消息的挑战为“ 0x0123456789abcdef ”)。
密码十六进制的Unicode字符串为“ 0x53006500630052004500740030003100 ”; 计算该值的MD4散列值,“ 0xcd06ca7c7e10c99b1d33b7485a2ed808 ”,这是NTLM哈希。
使用0填充到21个字节,得到“ 0xcd06ca7c7e10c99b1d33b7485a2ed8080000000000 ”。
将21字节分割成三部分“ 0xcd06ca7c7e10c9 ”,“ 0x9b1d33b7485a2e ”和“ 0xd8080000000000 ”。
三个密钥中的每一个用于对来质询消息的挑战(“ 0x0123456789abcdef ”)进行DES加密。
这会产生结果“ 0x25a98c1c31e81847 ”(使用我们的第一个键),“ 0x466b29b2df4680f3 ”(使用第二个键)和“ 0x9958fb8c213a9cc6 ”(使用第三个键)。
这三个密文值被连接在一起形成24字节的NTLM响应:0x25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6
NTLM版本2(“NTLMv2”)被用来解决NTLM中存在的安全问题。当启用NTLMv2时,NTLM响应被替换为NTLMv2响应,并且LM响应被替换为LMv2响应。
NTLMv2响应计算如下:
计算获得NTLM密码哈希,方法和上文一样。
计算获得 NTLMv2哈希值,先将用户名转换为大写,然后和目标拼接在一起(目标为 domain or server name 的值,且区分大小写)组成字符串,然后计算这个字符串的Unicode十六进制字符串,使用上文16字节NTLM散列作为密钥,将HMAC-MD5消息认证码算法应用于Unicode十六进制字符串,得到16字节的值,即为NTLMv2-HASH。
构建被称为“blob”的数据块。“blob”的数据块简述:
使用16字节NTLMv2散列(在上面步骤中计算)作为密钥,将HMAC-MD5消息认证码算法应用于质询消息的挑战与blob连接字符串。这会产生一个16字节的HASH输出值。该值与blob连接以形成NTLMv2响应。
使用上图NTLMv2数据包,计算NTLMv2响应示例:
计算获得 NTLMv2哈希值,先将用户名转换为大写
testapp --> TESTAPP
然后和domain拼接在一起(domain or server name 的值,且区分大小写)组成字符串
TESTAPPDESKTOP-DVIA6R3
然后计算这个字符串的Unicode十六进制字符串
54004500530054004100500050004400450053004B0054004F0050002D004400560049004100360052003300
使用上文16字节NTLM散列作为密钥,将HMAC-MD5消息认证码算法应用于Unicode十六进制字符串,得到16字节的NTLMv2
a92765662d236c31c620d365c89540d1
连接质询消息的挑战与blob得到字符串
4e783a49fe733dce0101000000000000891b7768f8b6d301bd64ae0fc8b412280000000002001e004400450053004b0054004f0050002d004d00490037004b0033003900560001001e004400450053004b0054004f0050002d004d00490037004b0033003900560004001e004400450053004b0054004f0050002d004d00490037004b0033003900560003001e004400450053004b0054004f0050002d004d00490037004b0033003900560007000800891b7768f8b6d30106000400020000000800300030000000000000000100000000200000cde827d049d6339086424b6e6880b54b98a279af64f927eb1db25b319c7d211e0a001000000000000000000000000000000000000900260063006900660073002f003100390032002e003100360038002e00310030002e00310030003200000000000000000000000000
使用NTLMv2散列(在上面步骤中计算)作为密钥,将HMAC-MD5消息认证码算法应用于此字符串,这会产生一个16字节的HASH输出值
03b4e9129fbe586e457d55412b39f324
该值与blob连接以形成NTLMv2响应
03b4e9129fbe586e457d55412b39f3240101000000000000891b7768f8b6d301bd64ae0fc8b412280000000002001e004400450053004b0054004f0050002d004d00490037004b0033003900560001001e004400450053004b0054004f0050002d004d00490037004b0033003900560004001e004400450053004b0054004f0050002d004d00490037004b0033003900560003001e004400450053004b0054004f0050002d004d00490037004b0033003900560007000800891b7768f8b6d30106000400020000000800300030000000000000000100000000200000cde827d049d6339086424b6e6880b54b98a279af64f927eb1db25b319c7d211e0a001000000000000000000000000000000000000900260063006900660073002f003100390032002e003100360038002e00310030002e00310030003200000000000000000000000000
然后我们发现这个和我们抓包看到的NTLMv2响应是一样的:
Hashcat的NTLMv2密码字典暴力破解应该就是还原上述过程对比ntlmv2_response,命令如下:
hashcat64.exe -m 5600 testapp::DESKTOP-DVIA6R3:4e783a49fe733dce:03b4e9129fbe586e457d55412b39f324:0101000000000000891b7768f8b6d301bd64ae0fc8b412280000000002001e004400450053004b0054004f0050002d004d00490037004b0033003900560001001e004400450053004b0054004f0050002d004d00490037004b0033003900560004001e004400450053004b0054004f0050002d004d00490037004b0033003900560003001e004400450053004b0054004f0050002d004d00490037004b0033003900560007000800891b7768f8b6d30106000400020000000800300030000000000000000100000000200000cde827d049d6339086424b6e6880b54b98a279af64f927eb1db25b319c7d211e0a001000000000000000000000000000000000000900260063006900660073002f003100390032002e003100360038002e00310030002e00310030003200000000000000000000000000 pwd.txt -o found.txt --force