NTLM认证详解
字数 1873 2025-08-11 17:40:15

NTLM认证协议详解

0x01 NTLM简介

NTLM(NT LAN Manager)是Windows操作系统提供的身份认证协议,主要功能包括:

  • 身份认证:采用challenge-response机制
  • 会话安全:支持消息签名和加密

认证流程:

  1. 服务器发送8字节随机数challenge
  2. 客户端根据密钥、challenge等信息计算response
  3. 服务器验证response是否匹配

0x02 NTLM消息结构

NTLM协议包含三种消息类型:

2.1.1 NEGOTIATE_MESSAGE

客户端发起协商,包含:

  • Signature:固定"NTLMSSP\0"
  • MessageType:0x00000001
  • NegotiateFlags:协商标志位
  • DomainName:客户端域名(可选)
  • Workstation:客户端工作组名(可选)

2.1.2 CHALLENGE_MESSAGE

服务器响应挑战,包含:

  • Signature:固定"NTLMSSP\0"
  • MessageType:0x00000002
  • ServerChallenge:8字节随机数
  • TargetName:服务器端名称(可选)
  • TargetInfo:服务器信息(可选)

2.1.3 AUTHENTICATE_MESSAGE

客户端认证响应,包含:

  • Signature:固定"NTLMSSP\0"
  • MessageType:0x00000003
  • LmChallengeResponse:LM响应
  • NtChallengeResponse:NTLM响应
  • DomainName:域名
  • UserName:用户名
  • Workstation:工作站名
  • EncryptedRandomSessionKey:加密的会话密钥(可选)
  • MIC:消息完整性校验(16字节)

0x03 NTLM认证类型

3.1 哈希类型

  • LM Hash:通过LMOWFv1计算
  • NTLM Hash:通过NTOWFv1计算
  • Net-NTLM Hash:客户端响应服务器挑战的数据

3.2 NTLM版本配置

通过注册表HKLM\SYSTEM\CurrentControlSet\Control\LsaLmCompatibilityLevel配置:

设置 描述
0 发送LM & NTLM响应 不使用NTLMv2
1 发送LM & NTLM - 如果协商使用NTLMv2 支持NTLMv2会话安全
2 仅发送NTLM响应 支持NTLMv2会话安全
3 仅发送NTLMv2响应 强制NTLMv2
4 仅发送NTLMv2响应/拒绝LM 拒绝LM
5 仅发送NTLMv2响应/拒绝LM & NTLM 强制NTLMv2

3.3 NTLM v1认证

3.3.1 LM Hash计算

def lm_hash(password:str):
    data = "KGS!@#$%".encode('utf-8')
    password = password.upper().encode("utf-8")
    if len(password) < 14:
        password += b'\x00'*(14-len(password))
    des1 = DES.new(des_7key28key(password[0:7]),DES.MODE_ECB)
    des2 = DES.new(des_7key28key(password[7:14]),DES.MODE_ECB)
    hash = des1.encrypt(data)+des2.encrypt(data)
    return hash

3.3.2 NTLM Hash计算

def ntlm_hash(password):
    hash = hashlib.new("md4",password.encode("utf-16le")).digest()
    return hash

3.3.3 Response计算

不启用NTLMv2会话安全

def ntlmv1_response(hash,server_challenge):
    return desl(hash,server_challenge)

启用NTLMv2会话安全

def ntlmv1_session(passwd:str,server_challenge:str,client_challenge:str):
    ntlmhash = ntlm_hash(passwd)
    challenge = server_challenge+client_challenge
    challenge_md5 = hashlib.md5(challenge).digest()
    lm_response = client_challenge+16*b'\x00'
    ntlm_reponse = ntlmv1_response(ntlmhash,challenge_md5[0:8])
    return lm_response,ntlm_reponse

3.4 NTLM v2认证

3.4.1 NTLMv2 Hash计算

def ntlmv2_hash(password,username,domain):
    ntlmhash = ntlm_hash(password)
    username = username.upper().encode('utf-16le')
    domain = domain.encode('utf-16le')
    ntlmv2hash = hmac.new(ntlmhash,username+domain,hashlib.md5).digest()
    return ntlmv2hash

3.4.2 Response计算

def ntlmv2(passwd,username,domain,server_challenge,client_challenge,timestamp,avpairs):
    ntlmv2hash = ntlmv2_hash(passwd,username,domain)
    temp = RespType_HiRespType_Reserved+timestamp+client_challenge+b'\x00'*4
    for avpair in avpairs:
        temp = temp + avpair
    temp = temp + b'\x00'*4
    NTProofStr = hmac.new(ntlmv2hash,server_challenge+temp,hashlib.md5).digest()
    ntlmv2_response = NTProofStr+temp
    lmv2_response = hmac.new(ntlmv2hash,server_challenge+client_challenge,hashlib.md5).digest()+client_challenge
    return lmv2_response,ntlmv2_response

0x04 会话安全

4.1 ExportedSessionKey生成

if (NTLMSSP_NEGOTIATE_KEY_EXCH bit is set):
    Set ExportedSessionKey to NONCE(16) # 16字节随机数
    Set EncryptedRandomSessionKey to RC4(KeyExchangeKey, ExportedSessionKey)
Else:
    Set ExportedSessionKey to KeyExchangeKey

4.2 KXKEY计算

NTLMv1不启用v2会话安全

def kxkey_ntlmv1_LMKEY(lm_hash,lm_response):
    des1 = DES.new(des_7key28key(lm_hash[0:7]),DES.MODE_ECB)
    des2 = DES.new(des_7key28key(lm_hash[7:8]+b'\xbd'*6),DES.MODE_ECB)
    return des1.encrypt(lm_response[0:8])+des2.encrypt(lm_response[0:8])

NTLMv1启用v2会话安全

def kxkey_ntlmv1_WITH_NT_SESSION(sessionbasekey,lm_response,server_challenge):
    return hmac.new(sessionbasekey,server_challenge+lm_response[0:8],hashlib.md5).digest()

4.3 SIGNKEY计算

用于消息完整性校验:

if (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY):
    if (Mode == "Client"):
        SignKey = MD5(ExportedSessionKey + "client-to-server signing key magic constant")
    else:
        SignKey = MD5(ExportedSessionKey + "server-to-client signing key magic constant")

4.4 SEALKEY计算

用于消息加密:

if (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY):
    if (NTLMSSP_NEGOTIATE_128):
        SealKey = ExportedSessionKey
    elif (NTLMSSP_NEGOTIATE_56):
        SealKey = ExportedSessionKey[0..6]
    else:
        SealKey = ExportedSessionKey[0..4]

0x05 安全特性

5.1 MIC(消息完整性校验)

使用ExportedSessionKey作为HMAC_MD5密钥,计算三个消息的哈希值,防止消息被篡改。

5.2 ChannelBinding

将服务器证书哈希存入AV_PAIR(MsvAvChannelBindings),防止中间人攻击。

0x06 攻击方法

6.1 Pass The Hash

利用已知的NTLM Hash计算NTLM Response,绕过密码验证。

6.2 NTLM Relay

中间人攻击,转发客户端的认证响应到服务器。

0x07 防御建议

  1. 禁用LM认证,使用NTLMv2
  2. 启用SMB签名
  3. 限制NTLM使用范围
  4. 启用EPA(Extended Protection for Authentication)
  5. 使用Kerberos替代NTLM

附录:完整Python实现

[见原文0x06节完整代码]

NTLM认证协议详解 0x01 NTLM简介 NTLM(NT LAN Manager)是Windows操作系统提供的身份认证协议,主要功能包括: 身份认证:采用challenge-response机制 会话安全:支持消息签名和加密 认证流程: 服务器发送8字节随机数challenge 客户端根据密钥、challenge等信息计算response 服务器验证response是否匹配 0x02 NTLM消息结构 NTLM协议包含三种消息类型: 2.1.1 NEGOTIATE_ MESSAGE 客户端发起协商,包含: Signature:固定"NTLMSSP\0" MessageType:0x00000001 NegotiateFlags:协商标志位 DomainName:客户端域名(可选) Workstation:客户端工作组名(可选) 2.1.2 CHALLENGE_ MESSAGE 服务器响应挑战,包含: Signature:固定"NTLMSSP\0" MessageType:0x00000002 ServerChallenge:8字节随机数 TargetName:服务器端名称(可选) TargetInfo:服务器信息(可选) 2.1.3 AUTHENTICATE_ MESSAGE 客户端认证响应,包含: Signature:固定"NTLMSSP\0" MessageType:0x00000003 LmChallengeResponse:LM响应 NtChallengeResponse:NTLM响应 DomainName:域名 UserName:用户名 Workstation:工作站名 EncryptedRandomSessionKey:加密的会话密钥(可选) MIC:消息完整性校验(16字节) 0x03 NTLM认证类型 3.1 哈希类型 LM Hash :通过LMOWFv1计算 NTLM Hash :通过NTOWFv1计算 Net-NTLM Hash :客户端响应服务器挑战的数据 3.2 NTLM版本配置 通过注册表 HKLM\SYSTEM\CurrentControlSet\Control\Lsa 的 LmCompatibilityLevel 配置: | 值 | 设置 | 描述 | |----|------|------| | 0 | 发送LM & NTLM响应 | 不使用NTLMv2 | | 1 | 发送LM & NTLM - 如果协商使用NTLMv2 | 支持NTLMv2会话安全 | | 2 | 仅发送NTLM响应 | 支持NTLMv2会话安全 | | 3 | 仅发送NTLMv2响应 | 强制NTLMv2 | | 4 | 仅发送NTLMv2响应/拒绝LM | 拒绝LM | | 5 | 仅发送NTLMv2响应/拒绝LM & NTLM | 强制NTLMv2 | 3.3 NTLM v1认证 3.3.1 LM Hash计算 3.3.2 NTLM Hash计算 3.3.3 Response计算 不启用NTLMv2会话安全 : 启用NTLMv2会话安全 : 3.4 NTLM v2认证 3.4.1 NTLMv2 Hash计算 3.4.2 Response计算 0x04 会话安全 4.1 ExportedSessionKey生成 4.2 KXKEY计算 NTLMv1不启用v2会话安全 : NTLMv1启用v2会话安全 : 4.3 SIGNKEY计算 用于消息完整性校验: 4.4 SEALKEY计算 用于消息加密: 0x05 安全特性 5.1 MIC(消息完整性校验) 使用ExportedSessionKey作为HMAC_ MD5密钥,计算三个消息的哈希值,防止消息被篡改。 5.2 ChannelBinding 将服务器证书哈希存入AV_ PAIR(MsvAvChannelBindings),防止中间人攻击。 0x06 攻击方法 6.1 Pass The Hash 利用已知的NTLM Hash计算NTLM Response,绕过密码验证。 6.2 NTLM Relay 中间人攻击,转发客户端的认证响应到服务器。 0x07 防御建议 禁用LM认证,使用NTLMv2 启用SMB签名 限制NTLM使用范围 启用EPA(Extended Protection for Authentication) 使用Kerberos替代NTLM 附录:完整Python实现 [ 见原文0x06节完整代码 ]