NTLM 认证协议
1. 什么是NTLM
在AD中,我们会遇到多种身份认证协议,其中Kerberos协议是最常见的,另一种协议 NTLM 尽管存在已知漏洞和加密弱点,但至今仍被广泛使用
1.1. NT Lan Manager
NT Lan Manager( NTLM / MS-NLMP)是一系列安全协议的名称,包括 LM 、 NTLMv1 和 NTLMv2 ,被各种基于 Windows 的网络上的应用协议用于验证远程用户,并在应用请求时可选地提供会话安全。 NTLM 安全协议都是嵌入式协议,这意味着尽管 NTLM 像其他协议一样具有消息和状态机,但它没有网络协议栈层。 NTLM 的这种特性允许任何在网络栈中定义了层的协议(例如 SMB 、 HTTP(s)和 LDAP(s))来利用它。对于使用它的应用协议, NTLMv2 提供了三种主要操作:
- 身份验证。
- 信息完整性(消息signing)
- 信息机密性(信息sealing)
1.2. 挑战-响应协议
NTLM 是一种挑战-响应协议,它使用 nonces(为一次性使用而生成的伪随机数)作为防御重放攻击的机制。尽管该协议有两种变体——面向连接和无连接,但我们主要只关注前者(有关两者之间的差异,请参阅MS-NLMP 中的概述部分)
1.3. NTLM SSP
与普通的协议实现不同,NTLM 最好被实现为一个可由应用协议调用的函数库,而不是网络协议栈中的一层。安全支持提供程序接口 (SSPI) 是 Windows 身份验证的基础,它是一个 API,允许连接的应用程序调用多个安全提供程序之一,以建立经过身份验证的连接并通这些连接安全地交换数据。
安全支持提供程序 (SSP) 是一个DLL,负责通过向应用程序公开一个或多个安全包来实现 SSPI;每个安全包提供应用程序的 SSPI 函数调用与实际安全模型函数之间的映射。这些安全包支持各种安全协议,包括NTLM
NTLM SSP(位于 %Windir%\System32\msv1_0.dll)是一种二进制消息协议,由 SSPI 调用,用于实现 NTLM 质询-响应身份验证,并协商完整性和机密性选项。NTLM SSP 涵盖了 NTLM 和 NTLMv2 身份验证协议。
加入域的计算机和工作站机器都可以使用NTLM进行身份验证
请记住以下内容
- 主机上使用的 NTLM 版本(无论是 NTLMv1 还是 NTLMv2)是在身份验证之前通过带外方式配置的。
- 通过一种安全机制,客户端与服务器/域控制器(DC)在身份验证之前共享一个密钥(用户密码的哈希值)。
- 明文凭据和共享密钥都不会在网络上传输。
1.4. 认证工作流程
加入域的计算机的 NTLM 身份验证工作流程始于客户端与服务器(所需服务所在的位置)交换特定于实现的应用协议消息,表明其想要进行身份验证。随后,客户端和服务器在身份验证期间交换三条特定的 NTLM 消息(嵌入在应用协议消息中):
- NEGOTIATE_MESSAGE(Type 1 消息)
- CHALLENGE_MESSAGE(Type 2 消息)
- AUTHENTICATE_MESSAGE(Type 3 消息)
一旦服务器收到 AUTHENTICATE_MESSAGE,由于它并不拥有客户端的密钥,服务器会通过调用 NetrLogonSamLogonWithFlags 将用户身份的验证委托给域控制器(DC)(这一过程称为直通身份验证 Pass-through authentication)。该调用包含 NETLOGON_NETWORK_INFO,这是一个填充了 DC 验证用户所需各字段的数据结构。如果身份验证成功,DC 会向服务器返回 NETLOGON_VALIDATION_SAM_INFO4 数据结构,随后服务器与客户端建立经过身份验证的会话;否则,DC 会返回错误,服务器可能会向客户端返回错误消息,或者直接终止连接。
下图是一个NTLM传递身份认证的流程
下面是工作站的验证流程,(直接由服务器验证用户身份,而非是委托给域控)
1.5. NTLM 消息
NTLM 消息的长度是可变的,头部为固定长度,消息载荷是可变的。头部始终以协议标识符和消息类型字段开始,根据消息类型的不同,消息可能包含额外的与消息相关的固定长度字段。这些字段之后是可变长度的消息载荷
| 字段 | 含义 |
|---|---|
| Signature | 一个 8 字节的以 NULL 结尾的 ASCII 字符串,始终设置为 [N, T, L, M, S, S, P, \0]。 |
| MessageType | 一个 4 字节无符号整数,始终设置为以下值之一:0x00000001 (NtLmNegotiate) 表示该 NTLM 消息是 NEGOTIATE_MESSAGE;0x00000002 (NtLmChallenge) 表示该 NTLM 消息是 CHALLENGE_MESSAGE;或者 0x00000003 (NtLmAuthenticate) 表示该 NTLM 消息是 AUTHENTICATE_MESSAGE。 |
| MessageDependentFields | 一个可变长度字段,包含 NTLM 消息内容。 |
| payload | 一个可变长度字段,包含与消息相关的若干个独立有效载荷消息,通过 MessageDependentFields 中的字节偏移量进行引用。 |
1.5.1. NEGOTIATE_MESSAGE 协商消息
NEGOTIATE_MESSAGE 是第一条特定于 NTLM 的消息,由客户端发送,表明其希望向服务器进行身份验证,并指定其支持或请求的 NTLM 选项。它包含四个与消息相关的固定长度字段。
其中一个需要了解的重要字段是 NegotiateFlags;这个 4 字节字段存在于所有三条 NTLM 消息中,并非 NEGOTIATE_MESSAGE 所特有。它是一个由 32 个 1 位标志组成的 NEGOTIATE 结构,用于指明发送方支持或请求哪些 NTLM 功能。
1.5.2. CHALLENGE_MESSAGE 挑战消息
CHALLENGE_MESSAGE 是第二条特定于 NTLM 的消息,由服务器发送给客户端,用于声明其能够支持的 NTLM 选项,并挑战客户端以证明其身份。
它包含六个与消息相关的固定长度字段,其中有两个需要重点了解:NegotiateFlags 和 ServerChallenge。NegotiateFlags 保存了服务器从客户端在 NEGOTIATE_MESSAGE 的 NegotiateFlags 字段中提供或请求的选项中所选择的标志。同时,ServerChallenge 是一个 64 位的随机数,保存了服务器生成的 NTLM 挑战值。
可以使用一些工具,如 NTLM Challenger, ntlm-info, NTLMRecon, DumpNTLMInfo.py来解析 CHALLENGE_MESSAGE 中返回的信息
python3 examples/DumpNTLMInfo.py 172.16.117.3
Impacket v0.12.0.dev1+20230803.144057.e2092339 - Copyright 2023 Fortra
[+] SMBv1 Enabled : False
[+] Prefered Dialect: SMB 3.0
[+] Server Security : SIGNING_ENABLED | SIGNING_REQUIRED
[+] Max Read Size : 8.0 MB (8388608 bytes)
[+] Max Write Size : 8.0 MB (8388608 bytes)
[+] Current Time : 2023-08-14 17:39:26.822236+00:00
[+] Name : DC01
[+] Domain : INLANEFREIGHT
[+] DNS Tree Name : INLANEFREIGHT.LOCAL
[+] DNS Domain Name : INLANEFREIGHT.LOCAL
[+] DNS Host Name : DC01.INLANEFREIGHT.LOCAL
[+] OS : Windows NT 10.0 Build 17763
[+] Null Session : True
1.5.3. AUTHENTICATE_MESSAGE 认证消息
AUTHENTICATE_MESSAGE 是第三条也是最后一条特定于 NTLM 的消息,由客户端发送给服务器,用以证明其拥有共享密钥。
它包含九个与消息相关的固定长度字段,其中有两个需要重点了解:LmChallengeResponseFields 和 NtChallengeResponseFields。对于 MS-NLMP 提供的伪代码,可以参考 Impacket 中 NTLM 的相关实现。
1.5.4. NTLMv1 响应计算
在身份验证过程中,如果双方协商启用了 NTLMSSP_NEGOTIATE_LM_KEY,客户端将根据协议版本构建不同的响应结构。
如果在 NegotiateFlags 中,服务器和客户端协商一致启用了 NTLMSSP_NEGOTIATE_LM_KEY(即 NEGOTIATE 消息中的 G 位),则响应结构如下:
对于 LmChallengeResponse 字段结构:
- NTLMv1 模式:使用 LM_RESPONSE 结构。
- Response:24 字节数组,存放客户端的 LmChallengeResponse。
- NTLMv2 模式:使用 LMv2_RESPONSE 结构。
- Response:16 字节数组,存放客户端的 LM 挑战响应。
- ChallengeFromClient:8 字节数组,存放客户端生成的挑战值。
MS-NLMP 提供了计算上述 Response 字段的 伪代码。
对于核心单向函数 (OWF):
- NTOWFv1:基于用户密码创建哈希,在 compute_nthash 函数中实现。计算时使用哈希结果而非明文密码。
- LMOWFv1:基于用户密码创建哈希,在 compute_lmhash 函数中实现。仅由 LM 和 NTLMv1 使用。
- 计算结果:客户端利用上述函数通过 computeResponseNTLMv1 完成最终响应。
对于 NtChallengeResponse Fields:
- 使用 NTLMv1,NtChallengeResponse 将包含一个 NTLM_RESPONSE 结构。
- 使用 NTLMv2,则 NtChallengeResponse 将包含一个 NTLMv2_RESPONSE 结构。
NTLM_RESPONSE:
- 包含一个字段 Response,这是一个 24 字节的无符号字符数组,其中包含客户端的 NtChallengeResponse。
NTLMv2_RESPONSE:
- 包含两个字段:Response 和一个 NTLMv2_CLIENT_CHALLENGE 结构。
- Response 是一个 16 字节的无符号字符数组,包含客户端的 NtChallengeResponse。
- NTLMv2_CLIENT_CHALLENGE 是一个可变长度的字节数组,包含八个固定长度的变量,其中包括 ChallengeFromClient。
如果我们使用 Responder(一个我们将在下一节学习的强大工具)捕获 NTLMv1 哈希,它将使用以下格式进行显示:
User::HostName:LmChallengeResponse:NtChallengeResponse:ServerChallenge:
[SMB] NTLMv1 Client : 172.19.117.36
[SMB] NTLMv1 Username : Support1
[SMB] NTLMv1 Hash : Support1::WIN-OLMHXGAP0V2:e2dL3196O8f55fB6:Q49S19A2937J6XC3CKA418EI4958OHB9:xF2K324O5L6Q7V8C
1.5.5. NTLMv2 响应计算
在身份验证过程中,对于 NTLMv2 响应计算:
若使用 Responder 捕获 NTLMv2 哈希,其显示格式如下:
User::Domain:ServerChallenge:Response:NTLMv2_CLIENT_CHALLENGE:
[SMB] NTLMv2-SSP Client : 172.19.117.55
[SMB] NTLMv2-SSP Username : INLANEFREIGHT\Support2
[SMB] NTLMv2-SSP Hash : Support2::INLANEFREIGHT:e2d2339638fc5fd6:D4979A923DD76BC3CFA418E94958E2B0:010100000000000000E0550D97CCD901509F9CE743AB58760000000002000800350034005800360001001E00570049004E002D00390038004B005100480054005300390048004200550004003400570049004E002D00390038004B00510048005400530039004800420055002E0035003400580036002E004C004F00430041004C000300140035003400580036002E004C004F00430041004C000500140035003400580036002E004C004F00430041004C000700080000E0550D97CCD901060004000200000008003000300000000000000000000000004000002DB95E9E27F0AD66CAA477372F555B500CFEA9C5A231FC68F0DA4FABFF76607E0A001000000000000000000000000000000000000900240063006900660073002F003100370032002E00310036002E003100310037002E00330030000000000000000000
1.6. NTLM 会话安全
1.7. 消息签名与密封
在 NTLM 认证和 SMB 通信的上下文中,Signing(签名)和 Sealing(密封)是确保会话安全的两大核心机制:
1.7.1. Signing (签名) —— 确保“完整性”
Signing 就像是在信封上盖了一个防伪印章。
1.7.2. Sealing (密封) —— 确保“机密性”
Sealing 就像是将信件放入一个保险箱。
- 作用: 消息密封通过对称加密机制提供消息保密性。
- 原理: 它会对整个消息载荷进行加密。
- 结果: 即使黑客在网络上截获了数据包,看到的也只是乱码,无法读取其中的实际内容。
- 注意: 在 NTLM 的上下文中,密封隐含了签名——也就是说,每一个被密封(加密)的消息也必然是经过签名(完整性校验)的。
| 特性 | Signing (签名) | Sealing (密封) |
|---|---|---|
| 安全目标 | 完整性 | 机密性 |
| 主要防范 | 数据篡改、中继攻击 | 数据窃听、隐私泄露 |
| 效果 | 能看到内容,但改不了 | 看不到内容,也改不了 |
| 版本支持 | NTLMv1 和 NTLMv2 均支持 | 仅 NTLMv2 支持 |
SMB签名的更新
由于攻击者经常用默认的 SMB 签名设置,微软发布了更新,在 Windows 11 Insider 版本(以及后续的主要版本)中强制启用 SMB 签名。
在以往的 Windows 10 和 11 中,默认仅在连接到名为 SYSVOL 和 NETLOGON 的共享时才要求 SMB 签名;而域控制器仅在任何客户端与其连接时才要求 SMB 签名。
消息密封
消息密封(Message sealing)通过实现对称密钥加密机制来提供消息的机密性;它确保客户端与服务器之间交换的消息内容保持安全,使攻击者无法读取或篡改。在 NTLM 的语境下,密封(sealing)也意味着签名(signing),因为每条经过密封的消息同时也都经过了签名。
1.8. 身份验证扩展保护(EPA)
Extended Protection for Authentication (EPA),基于 RFC 5056,是 Windows Server 2008 及后续版本中引入的一项功能,旨在增强 NTLM 认证的安全性。
- 建立安全通道:当 EPA 启用时,客户端和服务器会使用通道绑定令牌(CBT)建立一个安全通道。
- 绑定认证特性:CBT 将认证绑定到特定的通道特性(如 IP 地址和端口),从而防止认证在不同的通道上被重放。
- 协议支持:EPA 设计用于与 SMB 和 HTTP 协议配合工作,为依赖 NTLM 认证的应用程序和服务提供额外安全性。
- 前提条件:建立安全通道需要客户端和服务器双方都支持该功能。


