文章目录
0x01 前言简介
0x02 基本介绍
1.本地登录认证
2.网络登录认证
0x03 LM/NTLM 版本优缺
0x04 LM/NTLM 生成原理
1.LM-Hashes 生成实例
2.NTLM-Hashes 生成实例
0x05 LM/NTLM 挑战和响应机制原理
1.LAN Manager Challenge/Response
2.NTLM Challenge/Response
0x06 LM/NTLM C/R 协议分析
1.NTLMv1 C/R
2.NTLMv2 C/R
0x07 学习总结
0x08 参考来源
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,并准备登陆界面;若比较结果不同则登陆失败提示账号或者密码错误。
简单流程:
#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 格式:
#(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) 设置禁用;
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进制:
#二进制
第一组: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)进行加密
44EFCE164AB921CA
AAD3B435B51404EE
5.拼接得到的密码即形成LM-Hashes:44EFCE164AB921CAAAD3B435B51404EE
Python3实现LM-HASH脚本(需要安装pyDes模块):
运行:LM-Hashes.py
#!/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())
执行结果:
[root@WeiyiGeek F:\]$ Python LM-Hashes.py 123456Password:123456Hex: 31323334353631323334353600 0000000000000000110000100110001000110001100110010000101010100011011000000000000x30988c6642a8d800 0x0LM-Hashse Lower: 44efce164ab921caaad3b435b51404eeLM-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
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.查看lsass.exe进程信息;$tasklist|findstr"lsass.exe"lsass.exe 676 Services 0 35,172 K# 2.该程序在内存中的信息$procdump64.exe -ma -t 676ProcDump v9.0 - Sysinternals process dump utilityProcess: lsass.exe(676)Process image: C:\Windows\system32\lsass.exeCPU threshold: n/aPerformance counter: n/aCommit threshold: n/aThreshold seconds: n/aHung window check: DisabledLog debug strings: DisabledException monitor: DisabledException filter:[Includes]*[Excludes]Terminate monitor: EnabledCloning type: DisabledConcurrent limit: n/aAvoid outage: n/aNumber of dumps: 1Dump folder: C:\Users\Administrator\Downloads\Procdump\Dump filename/mask: PROCESSNAME_YYMMDD_HHMMSSQueue to WER: DisabledKill 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 dumpfilesize is 35 MB.[22:45:05]Dump 1 complete: 36 MB writtenin3.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$typepass.txtmimikatz(commandline)# sekurlsa::minidump lsass.dmpSwitch to MINIDUMP:'lsass.dmp'mimikatz(commandline)# sekurlsa::logonPasswords fullOpening:'lsass.dmp'fileforminidump...Logon Time:2020/3/8 11:30:23User Name:TestSID :S-1-5-21-1802160877-2963370050-2309095339-500msv:[00010000]CredentialKeys* NTLM:26b5936a9a6b7cd2d589abd4c6c126de* SHA1:fa6fe7fab3f9920f1e97ebd148767776e07e55b6
手动实现密码加密:
根据NTML HASH的生成原理推算也同样得到7b86d7692a8b1de47817434f08671229;
第一步:将WeiyiGeek进行十六进制的转换后输出结果如下;
WeiyiGeek=57 65 69 79 69 47 65 65 6b
第二步:将ASCII转码为Unicode(小端序)得到结果如下;
#注意:如果是使用UltraEdit进行转换成Unicode会带有FF FE,开头的FF FE用于标识此文本文件为Unicode编码String to Hex Unicode :770065006900790069006700650065006b00
第三步:将570065006900790069004700650065006b00(注意需要进行设置为Hex String)进行MD4加密后得到结果如下;
第四步:与上面内存中的NTLM HASH进行比较验证完成,自己拿取了大佬们写的JS库写的一个小Demo演示(在线加密的有很多,自己只是学习了解其中的算法思路才写的):
请输入需要加密成NTLM的明文密码: 转换结果: