{"record":{"id":"1392d616753c57fb","repo":"projectdiscovery/nuclei","slug":"ntlmssp-signature-not-found-in-response","errorCode":null,"errorMessage":"NTLMSSP signature not found in response","messagePattern":"NTLMSSP signature not found in response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"pkg/utils/telnetmini/ntlm.go","lineNumber":31,"sourceCode":"\tNetBIOSDomainName   string // NetBIOS_Domain_Name from script\n\tNetBIOSComputerName string // NetBIOS_Computer_Name from script\n\tDNSDomainName       string // DNS_Domain_Name from script\n\tDNSComputerName     string // DNS_Computer_Name from script\n\tDNSTreeName         string // DNS_Tree_Name from script\n\tProductVersion      string // Product_Version from script\n\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","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/utils/telnetmini/ntlm.go#L13-L49","documentation":"ParseNTLMResponse (pkg/utils/telnetmini/ntlm.go) implements the Nmap telnet-ntlm-info.nse logic: it searches the telnet sub-option payload for the ASCII 'NTLMSSP' signature. If absent, the server never sent NTLM data and parsing cannot proceed — this is the expected negative path for any host that does not negotiate NTLM over telnet.","triggerScenarios":"Calling ParseNTLMResponse on a telnet response from a non-Windows host (Linux telnetd, busybox, network gear) that answered the IAC DO ENCRYPT / IAC WILL ENCRYPT negotiation without NTLMSSP content; or calling it unconditionally on banners that never claimed NTLM support (skipping the supportsEncryption check from NegotiateEncryption).","commonSituations":"Network templates enumerating telnet info broadly across a /24; security scanning where most port-23 targets are embedded/Linux systems; template authors testing against a Windows lab and then running against mixed fleets.","solutions":["Gate the call: only parse NTLM when the encryption negotiation indicated support, or check bytes.Contains(data, []byte(\"NTLMSSP\")) first","Treat this error as 'NTLM not supported' — a normal finding, not a failure; make matchers/extractors handle its absence","Add template conditions (e.g. service detection or banner match) before running the NTLM telnet probe","Log it at debug/info level in custom tooling rather than surfacing as a scan error"],"exampleFix":"// before\ninfo, err := telnetmini.ParseNTLMResponse(resp)\nif err != nil { return err }\n\n// after\nif !bytes.Contains(resp, []byte(\"NTLMSSP\")) {\n    return nil // host does not speak NTLM over telnet; skip\n}\ninfo, err := telnetmini.ParseNTLMResponse(resp)\nif err != nil { return err }","handlingStrategy":"validation","validationCode":"// Cheap pre-check mirroring the parser's own first guard:\nif !bytes.Contains(raw, []byte(\"NTLMSSP\")) {\n    // server does not speak NTLM over telnet — skip, not an error\n    return nil, nil\n}\ninfo, err := telnetmini.ParseNTLMResponse(raw)","typeGuard":"func hasNTLMSignature(data []byte) bool {\n    return bytes.Index(data, []byte(\"NTLMSSP\")) != -1\n}","tryCatchPattern":"info, err := telnetmini.ParseNTLMResponse(resp)\nif err != nil {\n    if strings.Contains(err.Error(), \"signature not found\") {\n        return nil // expected on non-Windows hosts\n    }\n    return err // real parse problems propagate\n}","preventionTips":["Only call ParseNTLMResponse after the encryption negotiation reported NTLM support","Model 'no NTLM' as a normal outcome in template matchers","Test telnet-NTLM templates against a Windows lab host and a Linux host before shipping"],"tags":["telnet","ntlm","banner","windows","network-protocol"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}