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:
点击收藏 | 3 关注 | 1
登录 后跟帖