{"record":{"id":"249f4d41ee620086","repo":"projectdiscovery/nuclei","slug":"ntlm-response-not-properly-terminated-with-sub-opt","errorCode":null,"errorMessage":"NTLM response not properly terminated with Sub-option End","messagePattern":"NTLM response not properly terminated with Sub-option End","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/utils/telnetmini/ntlm.go","lineNumber":37,"sourceCode":"\tTimestamp           uint64 // Raw timestamp for skew calculation\n}\n\n// ParseNTLMResponse parses the NTLM response to extract system information\n// This implements the exact parsing logic from the Nmap telnet-ntlm-info.nse script\nfunc ParseNTLMResponse(data []byte) (*NTLMInfoResponse, error) {\n\t// Continue only if NTLMSSP response is returned.\n\t// Verify that the response is terminated with Sub-option End values as various\n\t// non Microsoft telnet implementations support NTLM but do not return valid data.\n\t// This matches the script's: local data = string.match(response, \"(NTLMSSP.*)\\xff\\xf0\")\n\tntlmStart := bytes.Index(data, []byte(\"NTLMSSP\"))\n\tif ntlmStart == -1 {\n\t\treturn nil, fmt.Errorf(\"NTLMSSP signature not found in response\")\n\t}\n\n\t// Find the end of NTLM data (Sub-option End: 0xFF 0xF0)\n\tntlmEnd := bytes.Index(data[ntlmStart:], []byte{0xFF, 0xF0})\n\tif ntlmEnd == -1 {\n\t\treturn nil, fmt.Errorf(\"NTLM response not properly terminated with Sub-option End\")\n\t}\n\n\t// Extract NTLM data (NTLMSSP.*\\xff\\xf0)\n\tntlmData := data[ntlmStart : ntlmStart+ntlmEnd]\n\n\t// Check message type (should be 2 for Challenge).\n\t// The fixed header runs to offset 48 (target-info offset field ends at byte 48),\n\t// so reject anything shorter before touching any field offsets.\n\tif len(ntlmData) < 48 {\n\t\treturn nil, fmt.Errorf(\"NTLM response too short: need at least 48 bytes, got %d\", len(ntlmData))\n\t}\n\n\tmessageType := binary.LittleEndian.Uint32(ntlmData[8:12])\n\tif messageType != 2 {\n\t\treturn nil, fmt.Errorf(\"expected NTLM challenge message, got type %d\", messageType)\n\t}\n\n\t// Parse target name fields","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/utils/telnetmini/ntlm.go#L19-L55","documentation":"ParseNTLMResponse found the NTLMSSP signature but no 0xFF 0xF0 (IAC SE, Sub-option End) terminator after it. Nmap's original regex (NTLMSSP.*\\xff\\xf0) requires the terminator because various non-Microsoft telnet implementations advertise NTLM but emit malformed or unterminated data; this guard rejects exactly those.","triggerScenarios":"A truncated telnet response — read deadline (1s per read in the negotiation loop) fired mid-NTLM payload; an IDS/IPS or firewall stripping sub-option bytes; a non-Windows implementation emitting NTLMSSP without proper SE framing; very slow servers whose NTLM blob arrives after the reader gave up.","commonSituations":"Scanning across WAN links with high latency (fixed 1-second read deadlines in telnet.go's negotiation loop are tight); middleboxes mangling telnet negotiation; embedded devices with half-baked NTLM implementations.","solutions":["Retry the probe — transient truncation over slow links often clears on a second attempt","Increase the negotiation timeout (the Client/Probe accepts a timeout parameter; default is 7s total) when integrating the telnetmini package directly","Treat as 'unsupported/malformed NTLM' and move on — do not fail the whole scan","If persistent, capture the raw bytes (hexdump) to check whether a middlebox is rewriting IAC sequences"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify terminator presence before invoking the parser:\nstart := bytes.Index(raw, []byte(\"NTLMSSP\"))\nif start == -1 { return nil, nil }\nif bytes.Index(raw[start:], []byte{0xFF, 0xF0}) == -1 {\n    return nil, fmt.Errorf(\"truncated NTLM (no IAC SE) — consider retry or larger timeout\")\n}\ninfo, err := telnetmini.ParseNTLMResponse(raw)","typeGuard":"func ntlmTerminated(data []byte) bool {\n    i := bytes.Index(data, []byte(\"NTLMSSP\"))\n    return i != -1 && bytes.Index(data[i:], []byte{0xFF, 0xF0}) != -1\n}","tryCatchPattern":"info, err := telnetmini.ParseNTLMResponse(resp)\nif err != nil && strings.Contains(err.Error(), \"not properly terminated\") {\n    info, err = nil, nil // truncated: retry once with longer timeout, else skip\n}","preventionTips":["Give telnet negotiation enough time on WAN links (raise the timeout parameter)","Read the full sub-option payload before parsing; don't parse partial reads","Expect non-compliant NTLM from embedded devices — treat as unsupported"],"tags":["telnet","ntlm","truncation","timeout","network-protocol"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}