LM-Hash与NTLM-Hash

在windows下通过SAMInside提取到的密码Hash时,可以看到有两条,分别是LM-Hash和NTLM-HASH
这是对同一个密码的两种不同的加密方式,下面对其生成原理做个实验。

Windows下LM-Hash生成原理(IBM设计的LM Hash算法)

实验环境:windows server 2003
使用工具:SAMinside

LM HASH生成规则如下:

  • 用户的密码被限制为最多14个字符。
  • 用户的密码转换为大写。
  • 密码转换为16进制字符串,不足14字节将会用0来再后面补全。
  • 密码的16进制字符串被分成两个7byte部分。每部分转换成比特流,并且长度位56bit,长度不足使用0在左边补齐长度,再分7bit为一组末尾加0,组成新的编码(str_to_key()函数处理)
  • 上步骤得到的8byte二组,分别作为DES key为"KGS!@#$%"进行加密。
  • 将二组DES加密后的编码拼接,得到最终LM HASH值。

测试服务器密码为123456

  • 用户的密码被限制为最多14个字符
  • 用户的密码转换为大写,大写转换后仍为它本身
  • 转换为16进制字符串后,结果为313233343536,不足14字节采用0进行补全,补全结果为3132333435360000000000000000
  • 固定长度的密码被分成两个7byte部分,也就是分为31323334353600和00000000000000,
    先把31323334353600转换为比特流,比特流为110001001100100011001100110100001101010011011000000000,长度不足56bit使用0在左边补齐长度,补齐后为00110001001100100011001100110100001101010011011000000000。
    再分7bit为一组末尾加0,组成新的编码,如下:
    0011000 0
    1001100 0
    1000110 0
    0110011 0
    0100001 0
    1010100 0
    1101100 0
    0000000 0
    此时的密码字符串为0011000010011000100011000110011001000010101010001101100000000000
    对应的8字节16进制编码(str_to_key()函数处理):30988C6692C8D000 ,同理知00000000000000对应的8字节16进制编码: 0000000000000000
  • 将以上步骤得到的两组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

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 |
  • 每组7字节做为参数传递给str_to_key()函数,最终得到三组DESKEY,每组8字节
    | C21A04748A0E9CCC | 5ED4B47642ACD428 | 0476800000000000 |
  • 分别用三组DESKEY对8字节挑战 "0001020304050607" 进行标准DES加密后得到
    C21A04748A0E9CCC ---- 对0001020304050607进行标准DES加密 --> CA1200723C41D577
    ​
    5ED4B47642ACD428 ---- 对0001020304050607进行标准DES加密 --> AB18C764C6DEF34F
    ​
    0476800000000000 ---- 对0001020304050607进行标准DES加密 --> A61BFA0671EA5FC8

Client A最终获得一个24字节响应应"CA1200723C41D577AB18C764C6DEF34FA61BFA0671EA5FC8"(这个结果被称为response)

  • Client A 将"CA1200723C41D577AB18C764C6DEF34FA61BFA0671EA5FC8" 送往Server B,Server B会根据自己缓存的LM-HASH进行同样的计算,并将计算结果与来自A的响应进行比较,如果匹配则身份验证通过

NTLM-HASH

IBM设计的LM Hash算法存在几个弱点,微软在保持向后兼容性的同时提出了自己的挑战响应机制,NTLM Hash便应运而生。

NTLM-HASH计算如下
密码为123456,首先将密码字符串转化为ASCII字符串,ASCII字符串再转换为十六进制字符串,十六进制字符串再转化为Unicode字符串,然后对Unicode字符串使用MD4消息摘要算法,这会产生一个16字节的值, NTLM-HASH

  • 转化为ASCII字符串 123456 ----> 49 50 51 52 53 54
  • 转换为十六进制字符串 49 50 51 52 53 54 ----> 31 32 33 34 35 36
  • 转化为Unicode字符串 31 32 33 34 35 36 ----> 310032003300340035003600
  • 使用MD4消息摘要算法 31 32 33 34 35 36 ----> 32ed87bdb5fdc5e9cba88547376818d4

计算结果与SAMinside提取结果相同
32ed87bdb5fdc5e9cba88547376818d4

各类HASH

NTLM消息介绍

NTLM验证是一种Challenge/Response 验证机制,由三种消息组成:通常称为类型1(协商),类型2(质询)和类型3(身份验证)。

它基本上是这样工作的:

  • 客户端向服务器发送类型1消息。这主要包含客户端支持的功能和服务器请求的功能列表。
  • 服务器用类型2消息进行响应。这包含服务器支持并同意的功能列表。然而,最重要的是,它包含了服务器产生的挑战。
  • 客户用类型3消息回复质询。这包含有关客户端的几条信息,包括客户端用户的域和用户名。它还包含对类型2挑战的一个或多个响应。(类型3消息中的响应是最关键的部分,因为它们向服务器证明客户端用户知道帐户密码。)

协商消息示例(此处为NTLMv2)

协商消息从客户端发送到服务器以启动NTLM身份验证。其主要目的是通过FLAG指明支持的选项来建立认证的“基本规则”。

十六进制协商消息:

4e544c4d53535000010000000732000006000600330000000b000b0028000000050093080000000f574f524b53544154494f4e444f4d41494e

将其分解如下:

wireshark 抓包分析协商消息数据包:

质询消息示例(此处为NTLMv2)

质询消息由服务器发送到客户端以响应客户端的协商消息。它用于完成与客户的选择的谈判,并且向客户提供挑战。它可以选择包含有关认证目标的信息。

十六进制质询消息:

4e544c4d53535000020000000c000c003000000001028100
0123456789abcdef0000000000000000620062003c000000
44004f004d00410049004e0002000c0044004f004d004100
49004e0001000c0053004500520056004500520004001400
64006f006d00610069006e002e0063006f006d0003002200
7300650072007600650072002e0064006f006d0061006900
6e002e0063006f006d0000000000

将其分解为其组成字段给出:

wireshark 抓包分析协商消息数据包:

身份验证消息示例(此处为NTLMv2)

身份验证消息
是身份验证的最后一步。该消息包含客户端对上一步挑战的响应,这表明客户知道账户密码而不直接发送密码。
身份验证消息
还指示身份验证目标(域或服务器名称)和身份验证帐户的用户名以及客户端工作站名称。

身份验证消息结构

客户端创建一个或多个挑战的响应,有六种类型的回应:

  • LM(LAN Manager)响应 - 由大多数较早的客户端发送,这是“原始”响应类型。
  • NTLM响应 - 这是由基于NT的客户端发送的,包括Windows 2000和XP。
  • NTLMv2响应 - 在Windows NT Service Pack 4中引入的一种较新的响应类型。它替换启用了NTLM版本2的系统上的NTLM响应。
  • LMv2响应 - 替代NTLM版本2系统上的LM响应。
  • NTLM2会话响应 - 用于在没有NTLMv2身份验证的情况下协商NTLM2会话安全性时,此方案会更改LM和NTLM响应的语义。
  • 匿名响应 - 当匿名上下文正在建立时使用; 没有提供实际的证书,也没有真正的身份验证。“存根”字段显示在类型3消息中。

wireshark 抓包分析身份验证消息数据包:

NTLM响应

NTLM响应由较新的客户端发送。该方案解决了LM响应中的一些缺陷; 然而,它仍然被认为相当薄弱。
此外,NTLM响应几乎总是与LM响应一起发送。该算法的弱点可以用来获取不区分大小写的密码,以及用于查找NTLM响应使用的区分大小写密码的试错法。

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

NTLMv2响应

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响应示例:

  • 首先算出密码123456789的NTLM,得到C22B315C040AE6E0EFEE3518D830362B
  • 计算获得 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

点击收藏 | 2 关注 | 1
登录 后跟帖