ntlm

package
v0.647.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

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.

func Decode

func Decode(hexStr string) (*Result, error)

Decode parses a single NTLM message from hex.

type Version

type Version struct {
	Major    int    `json:"major"`
	Minor    int    `json:"minor"`
	Build    int    `json:"build"`
	Revision int    `json:"ntlm_revision_current"`
	String   string `json:"string"`
}

Version is the decoded 8-byte VERSION structure.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL