Documentation
¶
Overview ¶
Package ntlm decodes NTLM (NT LAN Manager) messages per Microsoft Open Protocol Specifications MS-NLMP. NTLM is the challenge-response authentication protocol used pervasively on Windows networks:
- **SMB / CIFS** — SMB v1 / v2 / v3 sessions authenticate by exchanging NTLM Type 1 / 2 / 3 messages embedded in SESSION_SETUP_ANDX requests.
- **HTTP Negotiate / NTLM** — IIS, Exchange, SharePoint authenticate browser clients via "Authorization: NTLM <base64>" headers carrying NTLMSSP blobs.
- **LDAP / LDAPS** — Active Directory bind requests use NTLM as a SASL mechanism when Kerberos is unavailable.
- **MS-RPC over named pipes / DCERPC** — legacy SAM / LSAR / DRSUAPI traffic embeds NTLM in DCE bind PDUs.
NTLM is universally observed in Windows-heavy enterprise + AD-joined infrastructure, even in deployments that prefer Kerberos (NTLM remains a fallback for non-domain access, legacy applications, and stale device caches).
Wrap-vs-native judgement
Native. The MS-NLMP specification is public, and the wire format is straightforward: every NTLM message starts with the ASCII signature "NTLMSSP\x00" (8 bytes) followed by a 4-byte little-endian MessageType (1, 2, or 3) and a type-specific body. Each body is a fixed- position header that references variable-length payload data via (Length, MaxLength, Offset) field triples. No crypto at the parse layer — challenge bytes and responses are surfaced as hex; cryptographic verification requires the user's NT hash + IK / domain context.
What this package covers
**12-byte common header**: 8-byte ASCII signature "NTLMSSP\x00" (validated; mismatches return error) + 4-byte **MessageType** (little-endian uint32) with **3-entry name table**: 1 NEGOTIATE_MESSAGE (client → server), 2 CHALLENGE_MESSAGE (server → client), 3 AUTHENTICATE_MESSAGE (client → server).
**NEGOTIATE_MESSAGE (Type 1)** body:
4-byte **NegotiateFlags** (uint32 LE) decoded into a **~22-entry named-bit set** (see below).
8-byte Domain fields (Len + MaxLen + Offset).
8-byte Workstation fields.
Optional 8-byte **Version** (Major + Minor + Build uint16 LE + Reserved 3 bytes + NTLMRevisionCurrent byte = 0x0F).
Payload: Domain + Workstation strings (encoding per OEM/UNICODE flag).
**CHALLENGE_MESSAGE (Type 2)** body:
8-byte TargetName fields.
4-byte NegotiateFlags.
8-byte **ServerChallenge** (surfaced as hex — feeds into NTLM v1/v2 challenge-response hash crackable with hashcat mode 5500 / 5600).
8-byte Reserved.
8-byte TargetInfo fields (AV pair list).
Optional 8-byte Version.
Payload: TargetName + TargetInfo.
**AV Pair walker** (inside CHALLENGE_MESSAGE TargetInfo): (AvId uint16 LE + AvLen uint16 LE + Value) records ending at AvId 0 (MsvAvEOL). **10-entry AvId name table**: 1 MsvAvNbComputerName / 2 MsvAvNbDomainName / 3 MsvAvDnsComputerName / 4 MsvAvDnsDomainName / 5 MsvAvDnsTreeName / 6 MsvAvFlags / 7 MsvAvTimestamp / 8 MsvAvSingleHost / 9 MsvAvTargetName / 10 MsvAvChannelBindings.
**AUTHENTICATE_MESSAGE (Type 3)** body:
8-byte LmChallengeResponse fields.
8-byte NtChallengeResponse fields (surfaced as hex — feeds into NTLMv2 hash crackable with hashcat mode 5600; the structure also carries the NTProofStr that's the actual hash response).
8-byte DomainName fields.
8-byte UserName fields.
8-byte Workstation fields.
8-byte EncryptedRandomSessionKey fields.
4-byte NegotiateFlags.
Optional 8-byte Version.
Optional 16-byte MIC (Message Integrity Check).
Payload: response blobs + Domain + User + Workstation strings.
**NegotiateFlags name table** (~22 entries, RFC-less but well-documented in MS-NLMP §2.2.2.5): 0x00000001 NEGOTIATE_UNICODE / 0x00000002 NEGOTIATE_OEM / 0x00000004 REQUEST_TARGET / 0x00000010 NEGOTIATE_SIGN / 0x00000020 NEGOTIATE_SEAL / 0x00000040 NEGOTIATE_DATAGRAM / 0x00000080 NEGOTIATE_LM_KEY / 0x00000200 NEGOTIATE_NTLM / 0x00000800 ANONYMOUS_CONNECTION / 0x00001000 NEGOTIATE_OEM_DOMAIN_SUPPLIED / 0x00002000 NEGOTIATE_OEM_WORKSTATION_SUPPLIED / 0x00008000 NEGOTIATE_ALWAYS_SIGN / 0x00010000 TARGET_TYPE_DOMAIN / 0x00020000 TARGET_TYPE_SERVER / 0x00080000 NEGOTIATE_EXTENDED_SESSIONSECURITY / 0x00100000 NEGOTIATE_TARGET_INFO / 0x00200000 NEGOTIATE_IDENTIFY / 0x00400000 REQUEST_NON_NT_SESSION_KEY / 0x00800000 NEGOTIATE_TARGET_INFO_AV_PAIRS / 0x02000000 NEGOTIATE_VERSION / 0x20000000 NEGOTIATE_128 / 0x40000000 NEGOTIATE_KEY_EXCH / 0x80000000 NEGOTIATE_56.
What this package does NOT cover (deliberately out of scope)
Transport framing — feed the raw NTLMSSP bytes (already extracted from SMB SESSION_SETUP, HTTP "Authorization: NTLM <base64>", LDAP bind, or DCE bind PDU). Base64 decoding is the caller's job for HTTP-encoded blobs.
Cryptographic verification of NT/LM responses — surfaced as hex; verifying an NTLMv1 / NTLMv2 response requires the user's NT hash and the challenge from the matching Type 2 message (operators use hashcat mode 5500 / 5600 against the surfaced ServerChallenge + NtChallengeResponse).
MIC verification — surfaced as hex; verification requires the session key derived from KXKEY + SIGNKEY material that's not in the wire payload.
SPNEGO wrapper (when NTLM is the inner mechanism in a GSS-API negotiation) — strip the outer SPNEGO ASN.1 first; this decoder expects an NTLMSSP blob not wrapped in SPNEGO.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AVPair ¶
type AVPair struct {
AvID int `json:"av_id"`
AvIDName string `json:"av_id_name"`
AvLength int `json:"av_length"`
ValueHex string `json:"value_hex,omitempty"`
ValueText string `json:"value_text,omitempty"`
}
AVPair is one (AvId, AvLen, Value) record from the CHALLENGE TargetInfo list.
type AuthenticateBody ¶
type AuthenticateBody struct {
LmChallengeResponseHex string `json:"lm_challenge_response_hex,omitempty"`
LmChallengeResponseBytes int `json:"lm_challenge_response_bytes"`
NtChallengeResponseHex string `json:"nt_challenge_response_hex,omitempty"`
NtChallengeResponseBytes int `json:"nt_challenge_response_bytes"`
DomainName string `json:"domain_name,omitempty"`
UserName string `json:"user_name,omitempty"`
Workstation string `json:"workstation,omitempty"`
EncryptedSessionKeyHex string `json:"encrypted_session_key_hex,omitempty"`
NegotiateFlags uint32 `json:"negotiate_flags"`
NegotiateFlagsHex string `json:"negotiate_flags_hex"`
NegotiateFlagNames []string `json:"negotiate_flag_names"`
Version *Version `json:"version,omitempty"`
MICHex string `json:"mic_hex,omitempty"`
}
AuthenticateBody is the decoded body of a Type 3 AUTHENTICATE message.
type ChallengeBody ¶
type ChallengeBody struct {
TargetName string `json:"target_name,omitempty"`
TargetNameHex string `json:"target_name_hex,omitempty"`
NegotiateFlags uint32 `json:"negotiate_flags"`
NegotiateFlagsHex string `json:"negotiate_flags_hex"`
NegotiateFlagNames []string `json:"negotiate_flag_names"`
ServerChallenge string `json:"server_challenge_hex"`
ReservedHex string `json:"reserved_hex"`
TargetInfoHex string `json:"target_info_hex,omitempty"`
TargetInfoAVPairs []AVPair `json:"target_info_av_pairs,omitempty"`
Version *Version `json:"version,omitempty"`
}
ChallengeBody is the decoded body of a Type 2 CHALLENGE message.
type NegotiateBody ¶
type NegotiateBody struct {
NegotiateFlags uint32 `json:"negotiate_flags"`
NegotiateFlagsHex string `json:"negotiate_flags_hex"`
NegotiateFlagNames []string `json:"negotiate_flag_names"`
Domain string `json:"domain,omitempty"`
DomainHex string `json:"domain_hex,omitempty"`
Workstation string `json:"workstation,omitempty"`
WorkstationHex string `json:"workstation_hex,omitempty"`
Version *Version `json:"version,omitempty"`
}
NegotiateBody is the decoded body of a Type 1 NEGOTIATE message.
type Result ¶
type Result struct {
MessageType int `json:"message_type"`
MessageTypeName string `json:"message_type_name"`
TotalBytes int `json:"total_bytes"`
Negotiate *NegotiateBody `json:"negotiate_message,omitempty"`
Challenge *ChallengeBody `json:"challenge_message,omitempty"`
Authenticate *AuthenticateBody `json:"authenticate_message,omitempty"`
Notes []string `json:"notes,omitempty"`
}
Result is the top-level decoded view of an NTLM message.