[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%\System32\config\sam
)中,此时操作系统会自动地读取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,并准备登陆界面;若比较结果不同则登陆失败提示账号或者密码错误。
简单流程:
[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%\System32\config\sam
)中,此时操作系统会自动地读取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,并准备登陆界面;若比较结果不同则登陆失败提示账号或者密码错误。
简单流程:1 2 3 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 格式:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 aad3b435b51404eeaad3b435b51404ee : e19ccf75ee54e06b06a5907af13cef42 ca1200723c41d577ab18c764c6def34fa61bfa0671ea5fc8 NTLM Server Challenge: f9c7fc816b991824 Lan Manager Response: c67ee888f6b41a4400000000000000000000000000000000 NTLM Response: 293b99da834c86c6e37c37a20920b41581be32740a5e062e NTLM Server Challenge: f12d21c3e60843cc Lan Manager Response: 000000000000000000000000000000000000000000000000 LMv2 Client Challenge: 0000000000000000 NTLMv2 Hashes: 6061d067efff612ae4f1c704f1a44f08 NTProofStr: 32a48adf53baf6ef888482d94e222001 NTLMv2 Response: 32a48adf53baf6ef888482d94e2220010101000000000000...
0x04 LM/NTLM 生成原理 1.LM-Hashes 生成实例 注意:如果需要复现需要将系统策略进行更改支持LM存储:控制面板>所有控制面板项>管理工具>本地安全策略(gpedit.msc)>本地策略>安全选项>网络安全:在下一次更改密码时不存储LAN管理器哈希值(LM) 设置禁用
;
weiyigeek.top-在下一次更改密码时不存储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进制:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 第一组:31323334353600 == 110001001100100011001100110100001101010011011000000000 第二组:00000000000000 == 54 x 0 第一组:00110001001100100011001100110100001101010011011000000000 第二组:56 x 0 0011000 0 1001100 0 1000110 0 0110011 0 0100001 0 1010100 0 1101100 0 0000000 0 30988C6642A8D800 0000000000000000
weiyigeek.top-LM-Hashes
Python3实现LM-HASH脚本(需要安装pyDes模块): 运行:LM-Hashes.py1 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 68 69 70 71 72 73 74 import base64import binasciiimport sysfrom 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 : 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() test_str = test_str.upper() test_str = binascii.b2a_hex(test_str).decode(); print("Hex: " +test_str) str_len = len(test_str) if str_len < 28 : test_str = test_str.ljust(28 , '0' ) t_1 = test_str[0 :14 ] t_2 = test_str[14 :] t_1 = bin(int(t_1, 16 )).lstrip('0b' ).rjust(56 , '0' ) t_2 = bin(int(t_2, 16 )).lstrip('0b' ).rjust(56 , '0' ) t_1 = Zero_padding(t_1) t_2 = Zero_padding(t_2) 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) LM_1 = DesEncrypt("KGS!@#$%" , t_1) LM_2 = DesEncrypt("KGS!@#$%" , t_2) LM = LM_1 + LM_2 print("LM-Hashse Lower: " +LM.decode()+ "\nLM-Hashes Upper: " +LM.decode().upper())
执行结果:1 2 3 4 5 6 7 8 [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 1 2 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生成: 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 $tasklist | findstr "lsass.exe" lsass.exe 676 Services 0 35,172 K $procdump64 .exe -ma -t 676ProcDump v9.0 - Sysinternals process dump utility Process: lsass.exe (676) Process image: C:\Windows\system32\lsass.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:\Users\Administrator\Downloads\Procdump\ Dump filename/mask: PROCESSNAME_YYMMDD_HHMMSS Queue to WER: Disabled Kill after dump: Disabled $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. $mimikatz .exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit >pass.txt$type pass.txtmimikatz(commandline) Switch to MINIDUMP : 'lsass.dmp' mimikatz(commandline) 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进行十六进制的转换后输出结果如下;1 WeiyiGeek = 57 65 69 79 69 47 65 65 6b
第二步:将ASCII转码为Unicode(小端序)得到结果如下;1 2 String to Hex Unicode :770065006900790069006700650065006b00
第三步:将570065006900790069004700650065006b00(注意需要进行设置为Hex String)进行MD4加密后得到结果如下;
weiyigeek.top-
第四步:与上面内存中的NTLM HASH进行比较验证完成,自己拿取了大佬们写的JS库写的一个小Demo演示(在线加密的有很多,自己只是学习了解其中的算法思路才写的):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 <!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" > <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); 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.top-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 身份验证过程: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 [root@WeiyiGeek F:\]$ python LM-Hashes.py weiyigeek Password : weiyigeek LM-Hashse Lower: 623e80a2f48abcf1b3a121027af9fe24 LM-Hashes Upper: 623E80A2F48ABCF1B3A121027AF9FE24 LM-Hashes("weiyigeek" ) = 623e80a2f48abcf1b3a121027af9fe24; LM Challenge = 0001020304050607 623e80a2f48abcf1b3a121027af9fe24 0000000000 623e80a2f48abc f1b3a121027af9 fe240000000000 DESKEY 1 : 621ea0142ea42a78 DESKEY 2 : f0d8e8241012eaf2 DESKEY 3 : fe12000000000000 DESKEY 1 : 621ea0142ea42a78 -> 对Challenge 0001020304050607 进行标准DES加密 -> 5df3066f953edbd7 DESKEY 2 : f0d8e8241012eaf2 -> 对Challenge 0001020304050607 进行标准DES加密 -> c1573fddf1430e6f DESKEY 3 : fe12000000000000 -> 对Challenge 0001020304050607 进行标准DES加密 -> 2d124c5b2022bb6b Response Result : 5df3066f953edbd7c1573fddf1430e6f2d124c5b2022bb6b
weiyigeek.top-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.top-blob
在抓包中的关键字段是Blob目
weiyigeek.top-Blob
实际流程验证: 1 2 3 4 5 目标DOMAIN:HACKONE 用户名称:WeiyiGeek 密码NTLM:fc348d696833ec7ea33e121e8c41b69c (我直接采用上面的NTLM工具生成Hashes) Challenge:a47b80ee3b16910e Blob:01010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000
1.计算NTLMv2 Hashes值将用户名转换成为大写并且与domain(区分大小写)进行拼接,然后计算这个字符串的Unicode十六进制字符串(同样是小端序);
1 2 WEIYIGEEKHACKONE 570045004900590049004700450045004b004800410043004b004f004e004500
2.将密码NTLM Hashes作为密匙将HMAC-MD5消息认证码算法应用于Unicode十六进制字符串(运用于User+Domain)得到16字节的NTLMv2
1 2 6061d067efff612ae4f1c704f1a44f08
3.连接质询消息的挑战Challenge与blob得到字符串
1 a47b80ee3b16910e01010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000
3.将上面的NTLMv2散列作为密匙,将HMAC-MD5消息认证码算法应用于此字符串(Blob值与Challenge)消息产生一个16字节的HASH输出值
1 379a24c5f7fb068a140397f6ca2fd3d5
weiyigeek.top-
4.将上步生成的Hash值与blob连接进行拼接形成NTLMv2响应:1 379a24c5f7fb068a140397f6ca2fd3d501010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000
我们可以与下面NTLMv2协议抓包的Response进行对比:
weiyigeek.top-Responses
附录:小工具Console直接执行即可unicode转换:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var script = document .createElement('script' );script.src = "https://nf404.github.io/crypto-api/crypto-api.js" ; 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:1 reg add HKLM\SYSTEM\CurrentControlSet\Control\Lsa\ /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.top-NTLMv1
2) 质询消息示例 NTLM Message Type: NTLMSSP_CHALLENGE (0x00000002)1 NTLM Server Challenge: f9c7fc816b991824
weiyigeek.top-NTLMv2
备注:在许多的文章中都会说到NTLMv1生成的是8位的Challenge而NTLMv2生成的是16位的Challenge但是根据实际抓包的情况来看都是8Bytes(16位)的挑战;
3) 身份验证消息示例 NTLM Message Type: NTLMSSP_AUTH (0x00000003)1 2 Lan Manager Response: c67ee888f6b41a4400000000000000000000000000000000 NTLM Response: 293b99da834c86c6e37c37a20920b41581be32740a5e062e
weiyigeek.top-
备注:这里是区别采用是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.top-协商消息数据包
协商消息示例(十六进制):1 2 3 4 4e544c4d53535000 -- NTLMSSP签名(不会变化) 01000000 - NTLM消息类型1(谈判) mechToken: 4e544c4d5353500001000000978208e2000000000000000000000000000000000601b11d0000000f
示例说明:1 2 4e544c4d53535000010000000732000006000600330000000b000b0028000000050093080000000f574f524b53544154494f4e444f4d41494e
weiyigeek.top-分解
2) 质询消息示例 描述:质询消息由服务器发送到客户端以响应客户端的协商消息;它用于完成与客户的选择的谈判,并且向客户提供挑战,它可以选择包含有关认证目标的信息
。
关键字段:NTLM Message Type: NTLMSSP_CHALLENGE (0x00000002)
weiyigeek.top-质询消息数据库包
质询消息示例(主要参数):1 2 3 4 5 6 7 8 responseToken: 0x4e544c4d535350000 -- NTLMSSP签名(不会变化) 0x02000000 -- NTLM消息类型2(挑战) 0x15828ae2 -- 谈判标志 0x0a47b80ee3b16910e -- 服务器发的挑战 a182010b30820107a0030a0101a10c060a2b06010401823702020aa281f10481ee4e544c4d53535000020000001e001e003800000015828ae2a47b80ee3b16910e000000000000000098009800560000000a00ba470000000f4400450053004b0054004f0050002d004f004600510031004d0055004e0002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d50100000000
3) 身份验证消息示例 该消息包含客户端对上一步挑战的响应,这表明客户知道账户密码而不直接发送密码;并且还指示身份验证目标(域或服务器名称)和身份验证帐户的用户名以及客户端工作站
名称。
关键字段:NTLM Message Type: NTLMSSP_AUTH (0x00000003)
,此处根据NTLMv2 Response
字段能判断出采用v2协议:
weiyigeek.top-
身份验证消息结构示例(主要参数):1 2 3 4 5 6 7 8 9 10 responseToken: 4e544c4d53535000 -- NTLMSSP签名(不会变化) 03000000 -- NTLM消息类型3(认证) 000000000000000000000000000000000000000000000000 -- Lan Manager Response(对于老式系统认证使用) 0000000000000000 -- NTLMv2 Client Challenge: 379a24c5f7fb068a140397f6ca2fd3d501010000000000009b09b1969ef7d50166ce6f7781f3d3670000000002001e004400450053004b0054004f0050002d004f004600510031004d0055004e0001001e004400450053004b0054004f0050002d004f004600510031004d0055004e0004001e004400450053004b0054004f0050002d004f004600510031004d0055004e0003001e004400450053004b0054004f0050002d004f004600510031004d0055004e00070008009b09b1969ef7d5010600040002000000080030003000000000000000000000000030000013b5d33a3c720a8cf7789ac2bfb7d9ef82d7d476d546a70be02087c0e11c979d0a001000000000000000000000000000000000000900200063006900660073002f003100390032002e003100360038002e0031002e003500000000000000000000000000 66ce6f7781f3d367 -- NTLMv2 Client Challenge
weiyigeek.top-身份验证消息
从上面身份验证消息结构示例可以看到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.top-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) 参考资料
2) 文中工具