Documentation
¶
Overview ¶
Package smb2 decodes SMB2 / SMB3 (Server Message Block v2/v3) messages per [MS-SMB2] — the canonical Windows file-share and lateral-movement protocol. Runs over TCP/445 (direct host) + TCP/139 (NetBIOS Session Service framing).
Operationally, SMB2 is the **lateral-movement decoder** for every Windows pentest engagement. The wire format leaks:
**NTLM-relay vulnerability** — `NEGOTIATE_RESPONSE. SecurityMode` carries `SMB2_NEGOTIATE_SIGNING_ENABLED` (0x01) and `SMB2_NEGOTIATE_SIGNING_REQUIRED` (0x02). **When `SIGNING_REQUIRED` is NOT set, the server is vulnerable to NTLM relay attacks** (impacket `ntlmrelayx -t smb://target`). The decoder surfaces a `signing_required` boolean; canonical hardening audit primitive.
**SMB1 fallback / dialect downgrade** — NEGOTIATE_REQUEST dialect list often contains `0x0202` (SMB 2.0.2 — the lowest SMB2 dialect) alongside the wildcard `0x02FF` (`SMB2 ???`) indicator that the client also speaks SMB1. **Servers that respond to SMB1 are EternalBlue / WannaCry candidates** (MS17-010 — patched 2017 but lab + legacy environments still run unpatched). The decoder enumerates the offered dialects with name strings; presence of `0x02FF` flags the SMB1 advertise.
**Admin share access** — TREE_CONNECT_REQUEST carries the UNC path being mounted. Paths matching `\\<host>\ADMIN$` (Windows administrative root share), `\\<host>\C$` (full filesystem), `\\<host>\IPC$` (inter-process — required for MS-RPC over named pipes), or `\\<host>\<share>$` (any `$`-suffixed admin share) indicate privileged operations. The decoder surfaces `tree_connect_path`.
**Named-pipe lateral-movement vectors** — CREATE_REQUEST opens a file or named pipe under the mounted tree. Pipe paths reveal the attack: `\pipe\ spoolss` = PrintNightmare (CVE-2021-1675 / CVE-2021-34527 — abused for SYSTEM RCE on print spooler); `\pipe\netlogon` = ZeroLogon (CVE-2020-1472 — DC password reset); `\pipe\lsarpc` = LSA-policy access (used for SAM secrets dump via `lsadump::secrets`); `\pipe\samr` = AD account enumeration (`net user /domain` equivalent via MS-RPC); `\pipe\srvsvc` = Server Service (NetSessionEnum for session enum). The decoder surfaces `create_name`.
**Authentication failure feedback** — SESSION_SETUP_RESPONSE returns Status = `STATUS_LOGON_FAILURE` (0xC000006D), `STATUS_WRONG_PASSWORD` (0xC000006A), `STATUS_ACCOUNT_LOCKED_OUT` (0xC0000234), or `STATUS_PASSWORD_EXPIRED` (0xC0000071) on bad creds. Password-spray tools (cme, kerbrute) consume these directly. `STATUS_MORE_PROCESSING_REQUIRED` (0xC0000016) indicates a multi-step NTLMSSP / Kerberos exchange — keep reading. The decoder surfaces `status` + `status_name`.
**Server / Client GUID disclosure** — NEGOTIATE request + response carry a 16-byte GUID identifying the SMB endpoint. Combined with the SessionId, this is a stable fingerprint for tracking which client authenticated as which user.
Wrap-vs-native judgement
Native. MS-SMB2 is publicly documented (Microsoft Open Specifications); the SMB2 header is a fixed-shape 64-byte struct, little-endian throughout (unlike most network protocols which are BE). Per-command body decoding for NEGOTIATE / TREE_CONNECT / CREATE / SESSION_SETUP is straightforward; the remaining commands surface header fields only (sufficient for command-flow analysis). NTLM + Kerberos inner blobs are already handled by `ntlm_decode` + `kerberos_decode`. Compound-message chains, SMB3 encryption transform header, and lease / durable-handle state are out of scope.
What this package covers
**64-byte SMB2 header** ([MS-SMB2] §2.2.1): ProtocolId 0xFE 'S' 'M' 'B' (Sync) or 0xFD 'S' 'M' 'B' (Encrypted — Transform Header, surfaced as type-flag only) / StructureSize=64 / CreditCharge / Status (response) or ChannelSequence+Reserved (request) / Command (2) / CreditRequest|Response (2) / Flags (4) (incl. `SMB2_FLAGS_SERVER_TO_REDIR` 0x01 = response indicator, `SMB2_FLAGS_ASYNC_COMMAND` 0x02, `SMB2_FLAGS_RELATED_ OPERATIONS` 0x04 = compound chain, `SMB2_FLAGS_SIGNED` 0x08, `SMB2_FLAGS_PRIORITY_MASK` 0x70, `SMB2_FLAGS_DFS_OPERATIONS` 0x10000000, `SMB2_FLAGS_REPLAY_OPERATION` 0x20000000) / NextCommand (4) / MessageId (8) / AsyncId|(Reserved+TreeId) (8) / SessionId (8) / Signature (16).
**19-entry command name table** ([MS-SMB2] §2.2.1.2): 0x00 NEGOTIATE / 0x01 SESSION_SETUP / 0x02 LOGOFF / 0x03 TREE_CONNECT / 0x04 TREE_DISCONNECT / 0x05 CREATE / 0x06 CLOSE / 0x07 FLUSH / 0x08 READ / 0x09 WRITE / 0x0A LOCK / 0x0B IOCTL / 0x0C CANCEL / 0x0D ECHO / 0x0E QUERY_DIRECTORY / 0x0F CHANGE_NOTIFY / 0x10 QUERY_INFO / 0x11 SET_INFO / 0x12 OPLOCK_BREAK.
**6-entry SMB2 dialect name table** ([MS-SMB2] §2.2.3): 0x0202 SMB 2.0.2 / 0x0210 SMB 2.1 / 0x0300 SMB 3.0 / 0x0302 SMB 3.0.2 / 0x0311 SMB 3.1.1 / 0x02FF SMB2 wildcard (client advertises SMB1 capability — EternalBlue candidate indicator!).
**NEGOTIATE_REQUEST body** (§2.2.3): DialectCount (2) / SecurityMode (2) / Reserved (2) / Capabilities (4) / ClientGuid (16) / ClientStartTime|NegotiateContext OPTIONAL (8) / Dialects[DialectCount] (2 each). Surfaces `dialects` + `dialect_names` + `security_mode`
`signing_required` + `signing_enabled` + `smb1_offered` (presence of 0x02FF).
**NEGOTIATE_RESPONSE body** (§2.2.4): StructureSize (2) / SecurityMode (2) / DialectRevision (2) / NegotiateContextCount|Reserved (2) / ServerGuid (16) / Capabilities (4) / MaxTransactSize (4) / MaxReadSize (4) / MaxWriteSize (4) / SystemTime (8) / ServerStart Time (8) / SecurityBufferOffset (2) / SecurityBuffer Length (2) / NegotiateContextOffset|Reserved2 (4) / Buffer[]. Surfaces `dialect_chosen` + `dialect_chosen_ name` + `signing_required` + `signing_enabled` + `security_buffer_bytes` (length of GSS-API / SPNEGO blob).
**TREE_CONNECT_REQUEST body** (§2.2.9): StructureSize=9 / Flags|Reserved (2) / PathOffset (2) / PathLength (2) / Buffer[] (UNC path UTF-16LE). Surfaces `tree_connect_path` (decoded UTF-16LE; e.g. `\\dc01\ADMIN$`).
**CREATE_REQUEST body** (§2.2.13): StructureSize=57 / SecurityFlags / RequestedOplockLevel / ImpersonationL evel / SmbCreateFlags / Reserved / DesiredAccess / FileAttributes / ShareAccess / CreateDisposition / CreateOptions / NameOffset / NameLength / Create ContextsOffset / CreateContextsLength / Buffer[] (file name UTF-16LE). Surfaces `create_name` (decoded UTF-16LE; e.g. `pipe\spoolss`).
**15-entry NTSTATUS name table** ([MS-ERREF] §2.3): 0x00000000 STATUS_SUCCESS / 0x00000103 STATUS_PENDING (async I/O in progress) / 0xC0000016 STATUS_MORE_PROC ESSING_REQUIRED (multi-step NTLMSSP/Kerberos — keep reading) / 0xC0000022 STATUS_ACCESS_DENIED / 0xC0000034 STATUS_OBJECT_NAME_NOT_FOUND / 0xC0000061 STATUS_PRIV ILEGE_NOT_HELD / 0xC000006A STATUS_WRONG_PASSWORD / 0xC000006D STATUS_LOGON_FAILURE (canonical bad-creds response — password-spray feedback!) / 0xC0000071 STATUS_PASSWORD_EXPIRED / 0xC000007B STATUS_INVALID_I MAGE_FORMAT / 0xC00000BB STATUS_NOT_SUPPORTED / 0xC00000C9 STATUS_NETWORK_NAME_DELETED / 0xC0000128 STATUS_FILE_CLOSED / 0xC0000205 STATUS_INSUFF_SERVER _RESOURCES / 0xC0000234 STATUS_ACCOUNT_LOCKED_OUT.
What this package does NOT cover (deliberately out of scope)
- **NetBIOS Session Service framing** — when SMB2 rides over TCP/139 (NBSS), each PDU is prefixed with a 4-byte NBSS header (type=0x00 SESSION_MESSAGE, flags=0x00, length 17-bit BE). Strip the 4-byte NBSS header before feeding the decoder. TCP/445 has no NBSS prefix.
- **SESSION_SETUP NTLMSSP inner blob** — the SESSION_SETUP request/response SecurityBuffer carries the auth token (typically SPNEGO-wrapped NTLM NEGOTIATE / CHALLENGE / AUTHENTICATE or a Kerberos AP-REQ). When it contains an NTLMSSP message — located by the unambiguous 8-byte "NTLMSSP\0" signature, so a raw blob and a SPNEGO-wrapped one are both handled without parsing the SPNEGO ASN.1 — it is decoded in place via internal/ntlm (the NTLM-over-SMB relay / Responder / pass-the-hash capture: server challenge, target-info AV pairs, domain / user / workstation). A Kerberos (GSS-API) token has no such signature and is left for `kerberos_decode` after a SPNEGO strip; the SecurityBuffer length is surfaced either way.
- **Compound message chain** — NextCommand pointer chains multiple SMB2 commands in one packet; the decoder reports the first command only.
- **SMB3 encryption Transform header** (0xFD 'S' 'M' 'B' — [MS-SMB2] §2.2.41) — surfaced as `transform_header_present` flag only; the encrypted payload is opaque without the session key.
- **Per-command body decode beyond NEGOTIATE / TREE_CONNECT / CREATE** — READ / WRITE / IOCTL / QUERY_INFO bodies surfaced as header fields only.
- **Lease / durable / persistent handle state** — out of scope for the dissector pass.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Result ¶
type Result struct {
TotalBytes int `json:"total_bytes"`
TransformHeaderPresent bool `json:"transform_header_present"`
StructureSize int `json:"structure_size,omitempty"`
Command int `json:"command,omitempty"`
CommandName string `json:"command_name,omitempty"`
Flags uint32 `json:"flags,omitempty"`
IsResponse bool `json:"is_response"`
IsAsync bool `json:"is_async"`
IsCompound bool `json:"is_compound"`
IsSigned bool `json:"is_signed"`
NextCommand uint32 `json:"next_command,omitempty"`
MessageID uint64 `json:"message_id,omitempty"`
SessionID uint64 `json:"session_id,omitempty"`
TreeID uint32 `json:"tree_id,omitempty"`
Status uint32 `json:"status,omitempty"`
StatusName string `json:"status_name,omitempty"`
// NEGOTIATE
Dialects []uint16 `json:"dialects,omitempty"`
DialectNames []string `json:"dialect_names,omitempty"`
DialectChosen uint16 `json:"dialect_chosen,omitempty"`
DialectChosenName string `json:"dialect_chosen_name,omitempty"`
SecurityMode uint16 `json:"security_mode,omitempty"`
SigningEnabled bool `json:"signing_enabled"`
SigningRequired bool `json:"signing_required"`
SMB1Offered bool `json:"smb1_offered"`
SecurityBufferBytes int `json:"security_buffer_bytes,omitempty"`
// SESSION_SETUP — the SPNEGO/GSS-API security buffer. When it carries an
// NTLMSSP message (raw or SPNEGO-wrapped — the signature is found either
// way) it is decoded in place via internal/ntlm.
NTLMMessage *ntlm.Result `json:"ntlm_message,omitempty"`
// TREE_CONNECT
TreeConnectPath string `json:"tree_connect_path,omitempty"`
// CREATE
CreateName string `json:"create_name,omitempty"`
}
Result is the structured decode of an SMB2 message.