Windows认证原理解析基础入门

2022-09-29 15:55:22 浏览数 (1)

[TOC]

0x01 前言简介

本文借鉴安全界各位大佬所写的Windows认证入门科普(它们的站点我附在来源)对其中的知识点做了一个整理总结,同时复现里面的算法方便以后自己理解以及在其他域渗透/内网渗透方式中提供基础知识,这篇文章很适合小白入门Windows认证协议简单明了;

本文实验模拟在Windows 7 、Windows 10 下进行验证主要内容:

  • Windows用户认证基础介绍
  • LM/NTLM Hashes 版本优缺
  • LM/NTLM Hashes 生成原理
  • LM/NTLM Hashes 加密流程实践
  • LM/NTLM 挑战和响应(C/R)机制原理
  • LM/NTLM C/R 协议分析
  • 学习总结
0x02 基本介绍

描述:Hashes(散列)直接音译为“哈希-Hash”,是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。 简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数

回归到正题之中,有这样一个场景在您忘记您电脑密码的时候,我们常用的就是两种方式;

  • 1.采用PE系统进行跳过原始系统用户密码进行登录;
  • 2.进行PE系统中读取系统目录中SAM文件然后进行重新设置用户密码;

那SAM是什么呢?

SAM(Security Account Manage)是Windows系统中存放系统用户及密码的一种文件并采用Syskey(系统密钥)加密保护 而LM/NTLM 哈希存储在安全帐户管理器(SAM)数据库和域控制器的NTDS.dit数据库中 简单流程:用户登录的时候采用用户输入的密码进行NTLM Hashes加密然后与系统中SAM文件中存储的NTLM Hashes进行比对;

在这里不得不说一哈我们常用的NTLM Hashes的加密方式: NTLM Hashes它采用的MD4加密方式,目前应用最广泛的Hashes算法 MD5 和 SHA1 它们也都是参考MD4加密原理为基础设计的,下面简单说一下:

  • 1)MD4: (RFC 1320)是 MIT (麻省理工学院)的 Ronald L. Rivest 在 1990 年设计的,它是一种用来测试信息完整性的密码散列函数的实行。其MD(Message Digest)摘要长度为128位,一般128位长的MD4散列被表示为32位的十六进制数字。它适用在32位字长的处理器上用高速软件实现,它是基于 32 位操作数的位操作来实现的。
  • 2)MD5: (RFC 1321)是 Rivest于1991年对MD4的改进版本。它仍以512位分组来输入,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好
  • 3)SHA1: 由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。

回到正题由于当前PC常使用的系统版本基本都是Windows 7 / Windows 10,所以下认证情况都是基于该系统版本来说明的(作一个简单的了解):

1.本地登录认证

描述:当我们在本地登录认证时输入密码凭据登陆系统会首先将输入的凭据转换加密成NTLM Hashes(NT LAN Manager) 进行存储,这是由于Windows本身不存储用户的明文密码它将用户的明文密码经过加密算法后存储在SAM数据库(%SystemRoot%System32configsam)中,此时操作系统会自动地读取Windows系统中的SAM文件中的对应用户的NTLM hashes值进行与我们凭据生成的NTLM Hashes进行比对认证,认证完成则登录成功否则提示账号或者密码错误;

Windows本地登录验证流程:

  • 1.在我们注销或开机后将会弹出输入账号密码的界面用于接受用户输入由本地winlogon.exe进程进行管理;
    • 本地进程winlogon.exe将账号密码给lsass.exe进程进行处理并将密码缓存在进程中;
    • 本地进程lsass.exe将我们输入密码凭据转换为NTML Hashes读取SAM数据库与用户名进行比较;
  • 2.若比较结果相同则将User SID与Group SID发给winlogon.exe,并准备登陆界面;若比较结果不同则登陆失败提示账号或者密码错误。

简单流程:

代码语言:javascript复制
#Windows Logon Process winlogon.exe是 Windows NT 用户登陆程序用于管理用户登录和退出。
#Lsass.exe 是 用于微软Windows系统的安全机制它用于本地/远程安全和登陆策略,它会与我们SAM进行相互作用将本地或者远程身份认证的用户信息都会保存在其内存地址中。
winlogon.exe -> 接收用户输入 -> lsass.exe -> if (认证) { 登录成功 }else{ 登录失败 }
2.网络登录认证

局域网工作组:缺少信托机构(银行:两者之间进行交易所必须信任的中间人)

  • 工作组的环境是一个逻辑上的网络环境(工作区) ,隶属于工作组的机器之间无法互相建立一个完美的信任机制,只能点对点,是较为落后的认证方式没有信托机构。
  • 假设A主机与B主机在一个工作主组环境,A想要访问B主机上的资源,需要将一个存在于B主机上的账户凭证发送至B主机,经过认证才能访问B主机上的资源。传输数据由协议来规范数据如何传递,最常见的服务:SMB服务端口445 / RPC服务(Remote Procedure Call,远程过程调用) 135端口。
0x03 LM/NTLM 版本优缺

Windows用户认证LM/NTLM Hashes发展流程: 1) LM Hashes

IBM设计的LM Hash算法在Windows XP 或 Windows Server 2003 等系统发行版本以及以下采用的加密方式(基本已经被淘汰了);

LM Hashes版本系列说明:

  • LM Hashes
  • LM :完整名称(LAN Manager Challenge/Response) 挑战和验证机制主要用于网络身份认证;

2) NTLM Hashes

NTLM简称NT LAN Manager,由于LM Hashes脆弱性和Windows认证需要协议来规范,以及微软在保持向后兼容性的同时提出了WindowsNT挑战/响应验证机此时NTLM Hash便应运而生。 在Windows Vista 与 Windows Server 2008 以上版本默认采用的加密方式, NTLM Hashes算法的前身是LM Hashes

NTLM Hashes版本系列说明:

  • NTLM Hashes (也称为 NT Hashes) 主要用于本地认证;
  • NTLMv1 Hashes (也称为Net-NTLMv1 Hashes) 运用了WindowsNT挑战与响应验证机制结合,主要用于网络身份认证;
  • NTLMv2 Hashes (也称为Net-NTLMv2 Hashes) 主要用于网络身份认证并且使用广泛;
  • NTLM session 用于在没有NTLMv2身份验证的情况下协商NTLM2会话安全性时

说明:为了后面方便引用C/R验证机制的时候统一采用NTLMv1 Hashes 、NTLMv2 Hashes 进行说明;

LM / NTLM Hashes 两者之间优缺点比较:

  • 1.LM-Hashes
    • 缺点:安全问题密码不区分大小写(因为最开始会把密码统一转换为大写) 、密码最长为14位(2*7B==112bit)、可通过加密后的值反推加密前的密码位数、DES加密强度较弱等。
  • 2.NTLM-Hashes / Net-NTLM
    • 缺点:可以用来获取不区分大小写的密码,以及用于查找NTLM响应使用的区分大小写密码的试错法,特别是NTLMv1版本容易被彩虹表进行碰撞检测得出密码的NTLM Hashes。

LM / NTLM / Net-NTLM Hashes 格式:

代码语言:javascript复制
#(1) LM哈希(16B = 32字符 ) : NTLM哈希(16B = 32位)
aad3b435b51404eeaad3b435b51404ee : e19ccf75ee54e06b06a5907af13cef42

#(2) LM Pesponse(24B = 48位)
ca1200723c41d577ab18c764c6def34fa61bfa0671ea5fc8

#(3) NetNTLMv1 / NetNTLMv1 ESS
NTLM Server Challenge: f9c7fc816b991824
Lan Manager Response: c67ee888f6b41a4400000000000000000000000000000000
NTLM Response: 293b99da834c86c6e37c37a20920b41581be32740a5e062e

#(4) NET-NTLMv2(又名NTLMv2)哈希的示例
NTLM Server Challenge: f12d21c3e60843cc
Lan Manager Response: 000000000000000000000000000000000000000000000000
LMv2 Client Challenge: 0000000000000000
NTLMv2 Hashes: 6061d067efff612ae4f1c704f1a44f08 #(16 = 32位)
NTProofStr: 32a48adf53baf6ef888482d94e222001
NTLMv2 Response: 32a48adf53baf6ef888482d94e2220010101000000000000...#(128bit)

0x04 LM/NTLM 生成原理
1.LM-Hashes 生成实例

注意:如果需要复现需要将系统策略进行更改支持LM存储:控制面板>所有控制面板项>管理工具>本地安全策略(gpedit.msc)>本地策略>安全选项>网络安全:在下一次更改密码时不存储LAN管理器哈希值(LM) 设置禁用;

WeiyiGeek.在下一次更改密码时不存储LAN管理器哈希值(LM)

LM-Hashes生成原理三步骤详解:

  • Step0.由于这种密码生成规则要求用户的密码最多仅能为14个字符即14*8B=11bit长度
  • Step1.明文口令转换为其大写形式(Upper case)在有字母的情况下进行否者直接进行第二步
  • Step2.将转换后的口令进行转成Hex编码
  • Step3.生存的Hex编码如果不足112bit/8bit=14个字符要求用0补全
  • Step4.将补全后的14个字符112bit的数据分成2组每组7字节/B(56 bit)
  • Step5.将每组的十六进制转换成为二进制并且在转换后长度不足56bit使用0在左边补齐长度,再将二进制数据分7bit为一组末尾加0组成新的编码此时成为每组8B(64bit);
  • Step6.将上步得到的两组8B字节编码分别作为单向DES加密Key魔术字符串KGS!@#$%转换成为Hex(4B47532140232425)数据然后得到两组密文;
  • Step7.将两组DES加密后的数据进行拼接得到LM-Hash值;

实例验证LM-Hashes生成: 服务器密码:123456 LM-HASH值为:44EFCE164AB921CAAAD3B435B51404EE

1.由于服务器密码是纯数字转换任然为本身进行步骤跳过;

2.转换成为16进制的ASCII码不足14B采用0补齐并将补全结果分为两个7 Bytes部分即:31323334353600 00000000000000;

3.分别将两组7Bytes数据转换成为二进制进行补0操作后再分7bit一组在末尾 0,形成每组8B长度再将其转换成为16进制:

代码语言:javascript复制
#二进制
第一组:31323334353600 == 110001001100100011001100110100001101010011011000000000
第二组:00000000000000 == 54 x 0

#左边补0(2bit)
第一组:00110001001100100011001100110100001101010011011000000000
第二组:56 x 0

#再分7bit为一组末尾加0 (形成每组8B)
#第一组 / #第二组(全为0) 0000000 0 x 7 
0011000 0
1001100 0
1000110 0
0110011 0
0100001 0
1010100 0
1101100 0
0000000 0

#对此时的密码字符串对应的8字节16进制编码(str_to_key()函数处理)
30988C6642A8D800
0000000000000000

4.将以上步骤得到的两组16进制字符串,分别作为DES加密key为魔术字符串KGS!@#$%(Hex:4b47532140232425)进行加密

代码语言:javascript复制
44EFCE164AB921CA
AAD3B435B51404EE

WeiyiGeek.DES加密

5.拼接得到的密码即形成LM-Hashes:44EFCE164AB921CAAAD3B435B51404EE

WeiyiGeek.LM-Hashes

Python3实现LM-HASH脚本(需要安装pyDes模块): 运行:LM-Hashes.py

代码语言:javascript复制
#!/usr/bin/env python
# coding=utf-8
# Build Version: Python3
import base64
import binascii
import sys
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__":
    try:
      #将输入值进行Bytes转换
      print("Password : " sys.argv[1])
      test_str = sys.argv[1].encode('utf-8')
    except Exception as e:
      print("Usage:Python LM-Hashes.py Password")
      print("[*] Error:" str(e))
      sys.exit()
    # 用户的密码转换为大写,并转换为16进制ASCCI;
    test_str = test_str.upper()
    test_str = binascii.b2a_hex(test_str).decode();
    print("Hex: " test_str)
    str_len = len(test_str)

    # 密码不足14字节将会用0来补全
    if str_len < 28:
        test_str = test_str.ljust(28, '0')

    # 固定长度的密码被分成两个7byte部分
    t_1 = test_str[0:14]
    t_2 = test_str[14:]

    # print(t_1   " "   t_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-Hashse Lower: " LM.decode()  "nLM-Hashes Upper: " LM.decode().upper())

执行结果:

代码语言:javascript复制
[root@WeiyiGeek F:]$ Python LM-Hashes.py 123456
Password : 123456
Hex: 313233343536
31323334353600 00000000000000
0011000010011000100011000110011001000010101010001101100000000000
0x30988c6642a8d800 0x0
LM-Hashse Lower: 44efce164ab921caaad3b435b51404ee
LM-Hashes Upper: 44EFCE164AB921CAAAD3B435B51404EE
2.NTLM-Hashes 生成实例

NTLM-Hashes 生成原理步骤详解:

Step1:明文口令转换成16进制ASCII编码(Hex)

Step2:Unicode编码(ASCII转Unicode) 原本是在每个Hex编码前加上0x00nn,但是由于Window操作使用的是小端存储,所以得注意这里采用的是UTF-16小端序编码(LE,Little Endian|)即在每个字节之后添加00;

Step3:对Unicode字符串使用MD4消息摘要算法得到16字节的值即NTML-Hash

代码语言:javascript复制
NT_Hash(password) = MD4(UTF-16-LE(password))
NT_Hash("pass1") = "8D7A851DDE3E7BED903A41D686CD33BE"

补充知识点: 大端序(Big-Endian,大尾序):高位字节放在内存的低地址,低位字节放在内存的高地址, 低地址 0x12 0x34 0x56 0x78 高地址, 可以看见是符合人们常规得理解顺序。 小端序(Little-Endian,小尾序):低位字节放在内存的低地址,高位字节放在内存的高地址0x78 0x56 0x34 0x12,笑话:计算机说我也要由自己得理解顺序。

实例验证NTLM-Hases生成:

代码语言:javascript复制
# 1.查看lsass.exe进程信息;
$tasklist | findstr "lsass.exe"
lsass.exe                      676 Services                   0     35,172 K

# 2.该程序在内存中的信息
$procdump64.exe -ma -t 676
ProcDump v9.0 - Sysinternals process dump utility
Process:               lsass.exe (676)
Process image:         C:Windowssystem32lsass.exe
CPU threshold:         n/a
Performance counter:   n/a
Commit threshold:      n/a
Threshold seconds:     n/a
Hung window check:     Disabled
Log debug strings:     Disabled
Exception monitor:     Disabled
Exception filter:      [Includes]
                       *
                       [Excludes]
Terminate monitor:     Enabled
Cloning type:          Disabled
Concurrent limit:      n/a
Avoid outage:          n/a
Number of dumps:       1
Dump folder:           C:UsersAdministratorDownloadsProcdump
Dump filename/mask:    PROCESSNAME_YYMMDD_HHMMSS
Queue to WER:          Disabled
Kill after dump:       Disabled

#3.下载该应用程序在内存之中数据导出到本地以供mimikatz使用
$procdump64.exe -accepteula -ma lsass.exe lsass.dmp
[22:45:02] Dump 1 initiated: lsass.dmp
[22:45:05] Dump 1 writing: Estimated dump file size is 35 MB.
[22:45:05] Dump 1 complete: 36 MB written in 3.5 seconds
[22:45:06] Dump count reached.

#4.获取lsass.dmp文件内容并用mimikatz查看账户密码的NTML HASH值
$mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit >pass.txt

$type pass.txt
mimikatz(commandline) # sekurlsa::minidump lsass.dmp
Switch to MINIDUMP : 'lsass.dmp'
mimikatz(commandline) # sekurlsa::logonPasswords full
Opening : 'lsass.dmp' file for minidump...
Logon Time        : 2020/3/8 11:30:23
User Name         : Test
SID              :S-1-5-21-1802160877-2963370050-2309095339-500
msv :	
[00010000] CredentialKeys
* NTLM     : 26b5936a9a6b7cd2d589abd4c6c126de
* SHA1     : fa6fe7fab3f9920f1e97ebd148767776e07e55b6

手动实现密码加密: 根据NTML HASH的生成原理推算也同样得到7b86d7692a8b1de47817434f08671229; 第一步:将WeiyiGeek进行十六进制的转换后输出结果如下;

代码语言:javascript复制
WeiyiGeek = 57 65 69 79 69 47 65 65 6b

第二步:将ASCII转码为Unicode(小端序)得到结果如下;

代码语言:javascript复制
#注意:如果是使用UltraEdit进行转换成Unicode会带有FF FE,开头的FF FE用于标识此文本文件为Unicode编码
String to Hex Unicode :770065006900790069006700650065006b00

第三步:将570065006900790069004700650065006b00(注意需要进行设置为Hex String)进行MD4加密后得到结果如下;

WeiyiGeek.

第四步:与上面内存中的NTLM HASH进行比较验证完成,自己拿取了大佬们写的JS库写的一个小Demo演示(在线加密的有很多,自己只是学习了解其中的算法思路才写的):

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>MD4 加密 </title>
    <script src="https://nf404.github.io/crypto-api/crypto-api.min.js"></script>
    <script src="./md4.js"></script> 
</head>
<body>
    <p>请输入需要加密成NTLM的明文密码:</p>
    <label for="src">明文密码:</label><input type="text" value="" id="src"> &nbsp; &nbsp; 
    <input type="button" value="转换" onclick="ntlm_encoder()">
    <hr>
    <p>转换结果:</p>
    <p id="result"></p>
    <script>
        function ntlm_encoder(){
            var str = document.getElementById("src").value;
            var hex = "";
            for (i=0;i<str.length;i  ){
                hex  = str.charCodeAt(i).toString(16) "00";
            }
            resultASCII=CryptoApi.hash('md4', hex)
            resultUnicode=hex_md4(str); //采用16位 bits per input character 编码
            document.getElementById("result").innerHTML="<mark> String to Hex Unicode :"  hex   "<br> MD4 Text String : " resultASCII "<br> MD4 Hex String [NTLM]: " resultUnicode "</mark>";
        }
      </script>
</body>
</html>

WeiyiGeek.Demo演示


0x05 LM/NTLM 挑战和响应机制原理

问什么是挑战/响应模式(鉴权协议)?

答:鉴权协议如下的鉴权协议又被称作挑战(认证模式),使用明文口令模式时,网络上传输的就是明文口令本身很容易被Sniffer捕获。而挑战/响应模式在传输信道也是是可被侦听Sniffer,但不可被篡改的情况下并且对密码进行分段加密,这是一种简单而安全的方法。

1.LAN Manager Challenge/Response

描述:LM验证机制方案比NTLM响应时间更早,安全性更低。

以SMB通讯A(Client)/B(Server)访问请求为例: Step1.协商:通信连接请求TCP三次握手,采用SMB协议获取信息请求; Step2.质询:质询的完整过程

  • (1) A向B发送需要登录的用户验证是否存在,存在则继续否则失败
  • (2) B找到该用户的缓存的LM-Hash密码并且随机生成8B(16位)的挑战数,随后发送给A;
  • (3) A收到该16位挑战数(LM Challenge)并且将输入的密码转换成为LM-Hashes(Client A缓存输入密码的哈希值,原始密码会被丢弃,“原始密码在任何情况下都不能被缓存”,这是一条基本的安全准则)
  • (4) A将LM-Hashes(16B = 32字符) 加上5B(0X00)凑成21B(42个字符)然后划分成三组每组7字节,之后再对每组7字节做为参数传递给str_to_key()函数,最终得到三组DESKEY得到每组8字节的Hex数据;
  • (5) A分别采用上面所得24B数据(3组*8B)依次对Challenge(8B)进行标准DES加密并将其进行拼接最终得到一个24字节的响应数据(这就是我们所说的LM Response),随后发送给B;
  • (6) B也是根据4-6步骤生成本地的LM Pesponse Step3.响应验证:
  • (7) B收到A发送的Response后与本地生成的本地 LM Response进行比对,是则验证成功否则失败;

LM Challenge / Response 身份验证过程:

代码语言:javascript复制
#1.假设我们登录的账户是admin密码是weiyigeek(此时B机器上存在admin账户正确密码的LM-Hashes值)
[root@WeiyiGeek F:]$ python LM-Hashes.py weiyigeek
Password : weiyigeek
LM-Hashse Lower: 623e80a2f48abcf1b3a121027af9fe24
LM-Hashes Upper: 623E80A2F48ABCF1B3A121027AF9FE24

LM-Hashes("weiyigeek") = 623e80a2f48abcf1b3a121027af9fe24;

#2.B确认了Admin账户存在后之后生成8B的挑战并且向A进行发送;
LM Challenge = 0001020304050607

#3.A收到B发送的Challenge开始进行一些列生成LM Response流程
## 3.1 A输入的密码生成的LM-Hashse(16) 5B(0x00) = 21B
623e80a2f48abcf1b3a121027af9fe24 0000000000

## 3.2 将上步生成的21B数据平均分成三组(7B)
623e80a2f48abc f1b3a121027af9 fe240000000000

## 3.3 每组7字节做为参数传递给str_to_key()函数[就是将前面三组分别转成二进制然后7bit一组在后 0,最终形成8B数据再转回16进制]最终得到三组DESKEY
DESKEY 1 : 621ea0142ea42a78
DESKEY 2 : f0d8e8241012eaf2
DESKEY 3 : fe12000000000000

## 3.4 然后采用上面三组Key对进行Challenga加密后得到3组Hex字符拼接即可
DESKEY 1 : 621ea0142ea42a78 -> 对Challenge 0001020304050607 进行标准DES加密 -> 5df3066f953edbd7
DESKEY 2 : f0d8e8241012eaf2 -> 对Challenge 0001020304050607 进行标准DES加密 -> c1573fddf1430e6f
DESKEY 3 : fe12000000000000 -> 对Challenge 0001020304050607 进行标准DES加密 -> 2d124c5b2022bb6b

## 3.5得到最终的Response同时发送给B,B服务端采用相同的方式生成的Local LM Response进行比对,如果匹配则身份验证通过否则失败
Response Result : 5df3066f953edbd7c1573fddf1430e6f2d124c5b2022bb6b

WeiyiGeek.LM Response

2.NTLM Challenge/Response

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

  • NTLM版本1(“NTLMv1”)该方案解决了LM响应中的一些缺陷,但是同时自身由于NTLM响应几乎总是与LM响应一起发送所以比较薄弱(逆向推倒),在控制Challenge后可以在短时间内通过彩虹表还原出用户的ntlm hash;
  • NTLM版本2(“NTLMv2”)被用来解决NTLM中存在的安全问题。当启用NTLMv2时,NTLM响应被替换为NTLMv2响应,并且LM响应被替换为LMv2响应。

它们基本工作流程 Step1.协商:客户端向服务器发送类型1消息,确认协议版本是V1还是V2? Step2.质询:质询的完整过程服务器进行响应(重点:进行响应)

  • (1) 服务器判断用户是否存在:
    • 客户端向服务器端发送用户主机信息(必须包含用户名),服务器用客户端请求的用户名来判断服务器内是否有这个用户;
    • 若没有这个用户那么认证过程就是失败的;若有则继续:
  • (2) 服务器生成16位Challenge:
    • 服务器接受到请求之后生成一个16位随机数Challenge,服务器使用登录用户名对应的NTLM HASH;
  • (3) 服务器生成Net NTLM HASH便于比对:
    • 服务器用本机SAM文件数据库内NTLM HASH 加密 16位随机数 Challenge生成本地Response 即“Net-NTML HASH”
  • (4) 服务器返回16位Challenge:
    • 服务器将之前生成的16位随机数Challenge再发送给客户端;
  • (5) 客户端生成传送给服务端的Response:
    • 客户端接受到Challenge之后,使用将要登陆到账户对应的NTLM HASH加密Challenge生成Response,然后将Response发送到服务端 ;

Step3.类型验证:(最关键的部分因为它们向服务器证明客户端用户知道帐户密码)

  • (6) 服务端比对Response是否等于Net NTLM HASH: 比对服务器端收到客户端的Response后,比对NET NTLM HASH与Response是否相等,相等则通过。

1)NTLMv1 响应计算 Step1.首先本地生成输入密码的对应NTLM Hashes值; Step2.其次与LM C/R响应的计算方式是相同的(只是生产LM / NTLM Hashes不同而已),也是将16字节(32个字符)的NTLM散列填充为21个字节, Step3.分别将21Bytes分成3组7bit再将每组7字节做为参数传递给str_to_key()函数最终得到三组DESKEY(8bytes) Step4.将从服务器端接收的Challenge(质询消息的挑战)分别采用上面三组DESKEY进行加密得到三组DES加密的结果; Step5.将上面生成三组Des加密的结果进行拼接形成形成一个24字节的值这就是响应(Response)

说明:由于生成Response与LM C/R 一致所以这里不演示了,具体参考LM Challenge / Response 身份验证过程;

2)NTLMv2 响应计算 Step1.计算获取NTLM密码的Hashes参考前面实例验证NTLM-Hases生成; Step2.计算NTLMv2哈希值流程;

  • 1.先将用户名转换为大写然后和目标拼接在一起(目标为 domain or server name 的值,且区分大小写)组成字符串;
  • 2.然后计算这个字符串的Unicode十六进制字符串,使用Step1中的16字节NTLM散列作为密钥;
  • 3.将HMAC-MD5消息认证码算法应用于Unicode十六进制字符串,得到16字节的值即为NTLMv2-HASH
  • 4.使用16字节NTLMv2散列作为密钥,将HMAC-MD5消息认证码算法应用于质询消息的挑战(Challenge)与blob连接字符串,此时会产生一个16字节的HASH输出值,然后该值与blob连接以形成NTLMv2响应(Response)。

构建被称为“blob”的数据块其简述如下:

WeiyiGeek.blob

在抓包中的关键字段是Blob目

WeiyiGeek.Blob

实际流程验证:

代码语言:javascript复制
目标DOMAIN:HACKONE
用户名称:WeiyiGeek
密码NTLM:fc348d696833ec7ea33e121e8c41b69c (我直接采用上面的NTLM工具生成Hashes)
Challenge:a47b80ee3b16910e
Blob:01010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000

1.计算NTLMv2 Hashes值将用户名转换成为大写并且与domain(区分大小写)进行拼接,然后计算这个字符串的Unicode十六进制字符串(同样是小端序);

代码语言:javascript复制
WEIYIGEEKHACKONE
570045004900590049004700450045004b004800410043004b004f004e004500

2.将密码NTLM Hashes作为密匙将HMAC-MD5消息认证码算法应用于Unicode十六进制字符串(运用于User Domain)得到16字节的NTLMv2

代码语言:javascript复制
#注意这里都必须将Unicode转换Hex String获取的值才可以否则这将是个坑(怎么都复现不了)
6061d067efff612ae4f1c704f1a44f08

3.连接质询消息的挑战Challenge与blob得到字符串

代码语言:javascript复制
a47b80ee3b16910e01010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000

3.将上面的NTLMv2散列作为密匙,将HMAC-MD5消息认证码算法应用于此字符串(Blob值与Challenge)消息产生一个16字节的HASH输出值

代码语言:javascript复制
379a24c5f7fb068a140397f6ca2fd3d5

WeiyiGeek.

4.将上步生成的Hash值与blob连接进行拼接形成NTLMv2响应:

代码语言:javascript复制
379a24c5f7fb068a140397f6ca2fd3d501010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000

我们可以与下面NTLMv2协议抓包的Response进行对比:

WeiyiGeek.Responses

附录:小工具Console直接执行即可unicode转换:

代码语言:javascript复制
var script = document.createElement('script');
script.src = "https://nf404.github.io/crypto-api/crypto-api.js"; //支持HMAC-MD5但是仅仅传入的是字符串(而非Bytes);
document.getElementsByTagName('head')[0].appendChild(script);

var hostname="HACKONE";
var username="WeiyiGeek";
var ntlmhashes="fc348d696833ec7ea33e121e8c41b69c";
var str = username.toUpperCase() hostname;

function stringtoHex(str){
  var uhex='';
  for (i=0;i<str.length;i  ){
      uhex  = str.charCodeAt(i).toString(16) "00";
  }
  return uhex;
}

console.log(stringtoHex(str));

0x06 LM/NTLM C/R 协议分析
1.NTLMv1 C/R

描述:自Windows Vista/Server2008开始,系统默认禁用Net-NTLMv1如果使用Net-NTLMv2仅修改客户端即可服务器不用修改;

修改注册表开启Net-NTLMv1:

代码语言:javascript复制
reg add HKLMSYSTEMCurrentControlSetControlLsa /v lmcompatibilitylevel /t REG_DWORD /d 0 /f

以下采用协议抓的包进行简单的分析,同样采用smb关键字进行过滤smb and ip.addr==192.168.199.210,做个大概的说明其实与NTLMv2流程差别不大,仅仅是加密算法以及C/R位数不同(所以主要的还是看NTLMv2为主);

1) 协商消息示例

NTLM Message Type: NTLMSSP_NEGOTIATE (0x00000001)

WeiyiGeek.NTLMv1

2) 质询消息示例 NTLM Message Type: NTLMSSP_CHALLENGE (0x00000002)

代码语言:javascript复制
NTLM Server Challenge: f9c7fc816b991824

WeiyiGeek.NTLMv2

备注:在许多的文章中都会说到NTLMv1生成的是8位的Challenge而NTLMv2生成的是16位的Challenge但是根据实际抓包的情况来看都是8Bytes(16位)的挑战;

3) 身份验证消息示例 NTLM Message Type: NTLMSSP_AUTH (0x00000003)

代码语言:javascript复制
Lan Manager Response: c67ee888f6b41a4400000000000000000000000000000000  #如果采用了NTLMv2版本LM Response全为0
NTLM Response: 293b99da834c86c6e37c37a20920b41581be32740a5e062e

WeiyiGeek.

备注:这里是区别采用是NTLMv1与NTLMv2版本进行认证的,值得注意一下;

2.NTLMv2 C/R

描述:NTLM响应由较新的客户端发送且NTLMv2为当前使用最为广泛的协议版本;

考虑到网络认证协议有多个版本以及现有的环境下面此处以NTLMv2为例进行实际分析 环境说明: 192.168.1.6 A客户端 192.168.1.5 B服务器

1) 协商消息示例 描述:协商消息从客户端发送到服务器以启动NTLM身份验证,其主要目的是通过FLAG指明支持的选项来建立认证的“基本规则”。(此处参考:来源3)

名称解释:

NTLMSSP: Microsoft NTLM Security Support Provider;

Wrieshark抓取协商消息数据包过滤条件(smb2 and ip.addr==192.168.1.5),查找关键字段NTLM Message Type: NTLMSSP_NEGOTIATE (0x00000001)

WeiyiGeek.协商消息数据包

协商消息示例(十六进制):

代码语言:javascript复制
4e544c4d53535000 -- NTLMSSP签名(不会变化)
01000000 - NTLM消息类型1(谈判)

mechToken: 4e544c4d5353500001000000978208e2000000000000000000000000000000000601b11d0000000f

示例说明:

代码语言:javascript复制
#茜さす大佬的Hex我确实对应不上不知道是系统版本问题还是抓包工具不同的原因(求解-有知道的大佬可以在下面留个言)
4e544c4d53535000010000000732000006000600330000000b000b0028000000050093080000000f574f524b53544154494f4e444f4d41494e

WeiyiGeek.分解

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

关键字段:NTLM Message Type: NTLMSSP_CHALLENGE (0x00000002)

WeiyiGeek.质询消息数据库包

质询消息示例(主要参数):

代码语言:javascript复制
responseToken:
0x4e544c4d535350000 -- NTLMSSP签名(不会变化)
0x02000000 -- NTLM消息类型2(挑战)
0x15828ae2 -- 谈判标志
0x0a47b80ee3b16910e -- 服务器发的挑战

#Security Blob
a182010b30820107a0030a0101a10c060a2b06010401823702020aa281f10481ee4e544c4d53535000020000001e001e003800000015828ae2a47b80ee3b16910e000000000000000098009800560000000a00ba470000000f4400450053004b0054004f0050002d004f004600510031004d0055004e0002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d50100000000

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

关键字段:NTLM Message Type: NTLMSSP_AUTH (0x00000003),此处根据NTLMv2 Response字段能判断出采用v2协议:

WeiyiGeek.

身份验证消息结构示例(主要参数):

代码语言:javascript复制
responseToken:
4e544c4d53535000 -- NTLMSSP签名(不会变化)
03000000 -- NTLM消息类型3(认证)
000000000000000000000000000000000000000000000000 -- Lan Manager Response(对于老式系统认证使用)
0000000000000000 -- NTLMv2 Client Challenge:

#NTLM Response / NTLMv2 Response
379a24c5f7fb068a140397f6ca2fd3d501010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000

66ce6f7781f3d367 -- NTLMv2 Client Challenge

WeiyiGeek.身份验证消息

从上面身份验证消息结构示例可以看到A客户端创建一个或多个挑战的响应,大概有六种类型的回应:

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

4) 认证成功与失败示例

WeiyiGeek.Auth_Error

0x07 学习总结

描述:通过上面的学习以及加密原理的了解,可以针对于LM/NTLM有一个简单的入门了解,当我们在进行PTH攻击以及理解的时候是非常有用,并且有助于我们了解其他的Windows认证协议;

Net认证的Hash比较总结:

选项

LM-Hashes

NTLMv1

NTLMv2

密码区分大小写

散列密钥长度

56 bit 56 bit(112)

-

-

密码散列算法

DES(mode=ECB)

MD4

MD4

散列值的长度

64 64=128bit

128 bit

128 bit

C/R 密钥长度

56bit 56bit 18bit

56bit 56bit 18bit

128 bit

C/R 算法

DES(mode=ECB)

DES(mode=ECB)

HMAC_MD5

C/R 长度

64bit 64bit 64bit

64bit 64bit 64bit

128 bit


0x08 参考来源

1) 参考资料

  • 1.https://docs.microsoft.com/en-us/windows/win32/secauthn/microsoft-ntlm
  • 2.https://docs.microsoft.com/en-us/windows/win32/secauthn/microsoft-kerberos
  • 3.https://byt3bl33d3r.github.io/practical-guide-to-ntlm-relaying-in-2017-aka-getting-a-foothold-in-under-5-minutes.html
  • 4.https://www.insecurity.be/blog/2018/01/21/retrieving-ntlm-hashes-and-what-changed-technical-writeup/
  • 5.https://xz.aliyun.com/t/2445
  • 6.https://3gstudent.github.io/3gstudent.github.io/Windows下的密码hash-Net-NTLMv1介绍/

2) 文中工具

  • 1.进程内存数据提取:https://docs.microsoft.com/zh-cn/sysinternals/downloads/procdump
  • 2.MD4加密:https://nf404.github.io/crypto-api/crypto-api.min.js
  • 3.DEC编码加密:http://www.slavasoft.com/hashcalc/
  • 4.JS之MD4加密编码算法:https://www.iteye.com/blog/neil-yang-703462
  • 5.LM-NTLM脚本: https://xz.aliyun.com/t/2445
  • 6.Hashcat-Hashes破解格式:https://hashcat.net/wiki/doku.php?id=example_hashes
  • 7.自己: https://github.com/WeiyiGeek/SecOpsDev/tree/master/Cryption/DES/Python

0 人点赞