SSPI(Security Service Provider Interface 或 Security Support Provider Interface,安全服务提供接口) 是Windows定义的一套接口,该接口定义了与安全有关的功能函数,包括但不限于:
SSPI接口定义了与安全有关的功能函数,用来获取验证、信息完整性、信息隐私等安全功能,该接口知识定义了一套接口函数,但是并没有实现具体的内容。
SSP(Security Service Provider,安全服务提供者) 是SSPI的实现者,微软自己实现了如下的SSP,用于提供安全功能,包括但不限于:
因为SSPI中定义了与Session Security有关的API。所以上层应用利用任何SSP与远程的服务进行了身份验证后,此SSP都会为本次连接生成一个随机Key。这个随机Key被称为Session Key。上层应用经过身份验证后,可以选择性的使用这个Key对之后发往客户端或接受自服务端的数据进行签名或加密。在系统层面,SSP就是一个dll,用来实现身份验证登安全功能。不同的SSP,实现的身份验证机制是不一样的。比如NTLM SSP实现的就是一种基于质询/响应身份验证机制,而Kerberos SSP实现的就是基于Ticket票据的身份验证机制。可以自定义编写SSP,然后注册到操作系统中,让操作系统支持自定义的身份验证方法。
LM(LAN Manager)身份认证是微软推出的一个身份认证协议,其使用的机密算法是LM Hash加密算法。LM Hash本质是DES加密,尽管LM Hash较容易被破解,但为了保证系统的兼容性,Windows只是将LM Hash禁用了(Windows Vista和Windows Server 2008开始,Windows默认禁用了LM Hash)。LM Hash明文密码被限定在14位以内,也就是说,如果要停止使用LM Hash,将用户的密码设为14位以上即可。
LM Hash的值为:aad3b435b51404eeaad3b435b51404ee,说明LM Hash为空值或者被禁用了。
LM Hash加密流程:
加密实现代码:
# coding=utf-8 import base64 import binascii from pyDes import * import hashlib,binascii import md5 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 = raw_input("please input a string: ") # 用户的密码转换为大写 test_str = test_str.upper() print('\033[91m'+"转换为大写:"+'\033[0m') print(test_str) #转换为16进制字符串 test_str = test_str.encode('hex') print('\033[91m'+"转换为16进制字符串:"+'\033[0m') print(test_str) str_len = len(test_str) # 密码不足14字节将会用0来补全 if str_len < 28: test_str = test_str.ljust(28, '0') print('\033[91m'+"不足14字节(长度28),用0来补全:"+'\033[0m') print(test_str) # 固定长度的密码被分成两个7byte部分 t_1 = test_str[0:len(test_str) / 2] t_2 = test_str[len(test_str) / 2:] print('\033[91m'+"将14字节分为两组,每组7字节"+'\033[0m') print(t_1) print(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') print('\033[91m'+"转换为二进制数据,每组二进制数据长度为56比特位"+'\033[0m') print(t_1) print(t_2) # 再分7bit为一组末尾加0,组成新的编码 t_1 = Zero_padding(t_1) t_2 = Zero_padding(t_2) print('\033[91m'+"将每组二进制数据按7比特位为一组,分为8组,每组末尾加0"+'\033[0m') print(t_1) print(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') print('\033[91m'+"两组分别转换为16进制字符串"+'\033[0m') print(t_1) print(t_2) 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) print('\033[91m'+"上步骤得到的8byte二组,分别作为DES key为\"KGS!@#$%\"进行加密"+'\033[0m') print("LM_1:"+LM_1) print("LM_1:"+LM_2) # 将二组DES加密后的编码拼接,得到最终LM HASH值。 print('\033[91m'+"将二组DES加密后的编码拼接,得到最终LM HASH值"+'\033[0m') LM_Hash = LM_1 + LM_2 print ("LM_Hash:"+LM_Hash) 
为了解决LM Hash加密和身份验证方案中的安全弱点,微软与1993年在Windows NT 3.1中首次引入了NTLM Hash。微软从Windows Vista和Windows 2008开始,默认禁用了LM Hash,只存储NTLM Hash,而LM Hash的位置则为空。
NTLM Hash算法是微软为了在提高安全性的同时保证兼容性而设计的散列加密算法。NTLM Hash是基于MD4加密算法进行加密的。
NTLM Hash是由明文密码经过三步加密而成:
NTLM Hash =md4(unicode(hex(password)))
NTLM Hash的加密流程分为三步,具体如下:
实现代码:
# coding=utf-8 from Cryptodome.Hash import MD4 import binascii from cprint import cprint #转为16进制格式 def str_to_hex(string): return ' '.join([hex(ord(t)).replace('0x', '') for t in string]) #再将16进制格式的字符串进行ASCII转Unicode编码 def hex_to_unicode(string): return string.replace(" ","00")+"00" #最后对Unicode编码的16进制字符串进行标准MD4单向哈希加密 def unicode_to_md4(string): m = MD4.new() m.update(binascii.a2b_hex(string)) return m.hexdigest() if __name__ == "__main__": string = input("please input a string: ") HEX = str_to_hex(string) cprint.err("HEX编码:") print(HEX) Unicode = hex_to_unicode(HEX) cprint.err("ASCII转Unicode编码") print(Unicode) NTLm_Hash = unicode_to_md4(Unicode) cprint.err("对Unicode编码的16进制字符串进行标准MD4单向哈希加密得到NTLM Hash") print(NTLm_Hash) 
或者使用Python命令进行加密
python3 -c 'import hashlib,binascii; print("NTLM_Hash:"+binascii.hexlify(hashlib.new ("md4", "123456".encode("utf-16le")).digest()).decode("utf-8"))' 
用户密码经过NTLM Hash机密后存储在 %SystemRoot%\system32\config\SAM 文件里。
当用户输入密码进行本地认证的过程中,所有的操作都是在本地进行的。系统将用户输入的密码转换为NTLM Hash,然后与SAM文件中的NTLM Hash进行比较,相同说明密码正确,反之错误。当用户注销、重启、锁屏后,操作系统会让winlogon.exe显示登录界面,也就是输入框。当winlogon.exe接收收入后,将密码交给lsass.exe进程,lsass.exe进程中会存一份明文密码,将明文密码加密成NTLM Hash,与SAM数据库进行比较认证。使用mimikatz就是从lsass.exe进程中抓取明文密码或密码Hash。
一般抓取到的密码格式第一部分是用户名,第二部分是用户的SID值,第三部分是LM Hash,第四部分是NTLM Hash,其余部分为空。
NTLM身份认证协议是一种基于Challenge/Response质询响应验证机制,由三种类型消息组成。
NTLM身份认证协议有NTLM v1和NTLM v2两个版本,目前使用最多的是NTLM v2版本。他们之间最显著的区别就是Challenge质询值与加密算法不同,共同之处就是都是使用NTLM Hash进行加密。
工作组环境下NTLM认证流程可以分为4个步骤
域环境下的NTLM认证流程可以分为6个步骤:
NTLM v1 身份认证协议和 NTLM v2 身份认证协议是 NTLM 身份认证协议的不同版本。目前使用最多的是 NTLM v2 版本。NTLM v1 与 NTLM v2 最显著的区别就 是 Challenge 质询值与加密算法不同,共同之处就是都是使用的 NTLM Hash 进 行加密。
Challenge质询值
Net-NTLM Hash使用的加密算法
LmCompatibilityLevel 值用来确定网络登录使用的质询/响应身份验证协议。此选 项会影响客户端使用的身份验证协议的等级、协商的会话安全的等级以及服务器接 受的身份验证的等级,如下是 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 身份验证。 |
如何手动进行修改?
打开本地安全策略–》安全设置–》本地策略–》安全选项–》网络安全:LAN管理器身份验证级别,默认其值是没有定义的,使用默认值
从上面 NTLM 认证的流程中我们可以看到,在 Type 3 Auth 认证消息中是使用用户密码的 Hash 计算的。因此当我们没有拿到用户密码的明文而只拿到 Hash 的情况下,我们可以进行 **Pass The Hash(PTH)攻击,也就是哈希传递攻击。同样,还是在 Type3 消息中,存在 Net-NTLM Hash,当攻击者获得了 Net- NTLM Hash 后,可以进行中间人攻击,重放 Net-NTLM Hash,这种攻击手法也就是NTLM Relay(NTLM 中继)**攻击。并且由于 NTLM v1 版本协议加 密过程存在天然缺陷,可以对 Net-NTLM v1 Hash 进行爆破,得到 NTLM Hash。拿到 NTLM Hash 后即可进行横向移动。
Pass The Hash(PTH)哈希传递攻击是内网横向移动的一种方式。主要原因是 NTLM 认证过程中使用的是用户密码的 NTLM Hash 来进行加密。因此当我们获取到了用户密码的 NTLM Hash 而没有解出明文时,我们可以利用该 NTLM Hash 进行哈希传递攻击,对内网其他机器进行 Hash 碰撞,碰撞到使用相同密码的机器。然后通过 135 或 445 端口横向移动到使用该密码的其他机器。
NTLM Relay 其实严格意义上并不能叫 NTLM Relay,而是应该叫 Net-NTLM Relay。它是发生在 NTLM 认证的第三步,在 Response 消息中存在 Net-NTLM Hash,当攻击者获得了 Net-NTLM Hash 后,可以进行中间人攻击,重放 Net- NTLM Hash,这种攻击手法也就是 NTLM Relay(NTLM 中继)攻击。
由于 NTLM v1 身份认证协议加密过程存在天然缺陷,只要获取到 Net-NTLM v1 Hash,都能破解为 NTLM hash,这与密码强度无关。在域环境中这更有效,因为域中使用 hash 即可远程连接目标机器。如果域控允许发送 NTLM v1 响应的话, 我们就可以通过与域控机器进行 NTLM 认证,然后抓取域控的 Net-NTLM v1 Hash,破解为 NTLM Hash。使用域控的机器账号和哈希即可导出域内所有用户哈希。