projectdiscovery/nuclei · info
NTLMSSP signature not found in response
Error message
NTLMSSP signature not found in response
What it means
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.
Source
Thrown at pkg/utils/telnetmini/ntlm.go:31
NetBIOSDomainName string // NetBIOS_Domain_Name from script
NetBIOSComputerName string // NetBIOS_Computer_Name from script
DNSDomainName string // DNS_Domain_Name from script
DNSComputerName string // DNS_Computer_Name from script
DNSTreeName string // DNS_Tree_Name from script
ProductVersion string // Product_Version from script
Timestamp uint64 // Raw timestamp for skew calculation
}
// ParseNTLMResponse parses the NTLM response to extract system information
// This implements the exact parsing logic from the Nmap telnet-ntlm-info.nse script
func ParseNTLMResponse(data []byte) (*NTLMInfoResponse, error) {
// Continue only if NTLMSSP response is returned.
// Verify that the response is terminated with Sub-option End values as various
// non Microsoft telnet implementations support NTLM but do not return valid data.
// This matches the script's: local data = string.match(response, "(NTLMSSP.*)\xff\xf0")
ntlmStart := bytes.Index(data, []byte("NTLMSSP"))
if ntlmStart == -1 {
return nil, fmt.Errorf("NTLMSSP signature not found in response")
}
// Find the end of NTLM data (Sub-option End: 0xFF 0xF0)
ntlmEnd := bytes.Index(data[ntlmStart:], []byte{0xFF, 0xF0})
if ntlmEnd == -1 {
return nil, fmt.Errorf("NTLM response not properly terminated with Sub-option End")
}
// Extract NTLM data (NTLMSSP.*\xff\xf0)
ntlmData := data[ntlmStart : ntlmStart+ntlmEnd]
// Check message type (should be 2 for Challenge).
// The fixed header runs to offset 48 (target-info offset field ends at byte 48),
// so reject anything shorter before touching any field offsets.
if len(ntlmData) < 48 {
return nil, fmt.Errorf("NTLM response too short: need at least 48 bytes, got %d", len(ntlmData))
}
View on GitHub (pinned to 265b3a3dec)
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
Example fix
// before
info, err := telnetmini.ParseNTLMResponse(resp)
if err != nil { return err }
// after
if !bytes.Contains(resp, []byte("NTLMSSP")) {
return nil // host does not speak NTLM over telnet; skip
}
info, err := telnetmini.ParseNTLMResponse(resp)
if err != nil { return err } Defensive patterns
Strategy: validation
Validate before calling
// Cheap pre-check mirroring the parser's own first guard:
if !bytes.Contains(raw, []byte("NTLMSSP")) {
// server does not speak NTLM over telnet — skip, not an error
return nil, nil
}
info, err := telnetmini.ParseNTLMResponse(raw) Type guard
func hasNTLMSignature(data []byte) bool {
return bytes.Index(data, []byte("NTLMSSP")) != -1
} Try / catch
info, err := telnetmini.ParseNTLMResponse(resp)
if err != nil {
if strings.Contains(err.Error(), "signature not found") {
return nil // expected on non-Windows hosts
}
return err // real parse problems propagate
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- NTLM response not properly terminated with Sub-option End
- NTLM response too short: need at least 48 bytes, got %d
- expected NTLM challenge message, got type %d
- failed to send MS-TNAP login packet: %w
- no response received
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/1392d616753c57fb.
Report an issue: GitHub.