shadow1ng/fscan · error
failed to negotiate: %s
Error message
failed to negotiate: %s
What it means
This error wraps a failure of smbClientNegotiate during smb1AnonymousConnectIPC (plugins/services/ms17010_exp.go:147). Negotiation sends a hardcoded SMB1 Negotiate Protocol request and reads the reply via smb1GetResponse; any transport failure or malformed reply is surfaced here. It means the TCP connection was established but the SMB protocol handshake did not complete.
Source
Thrown at plugins/services/ms17010_exp.go:147
buf.Write(size)
buf.Write(sc)
return buf.Bytes()
}
func smb1AnonymousConnectIPC(address string) (*smbHeader, net.Conn, error) {
conn, err := net.DialTimeout("tcp", address, 10*time.Second)
if err != nil {
return nil, nil, fmt.Errorf("failed to connect host: %s", err)
}
var ok bool
defer func() {
if !ok {
_ = conn.Close()
}
}()
err = smbClientNegotiate(conn)
if err != nil {
return nil, nil, fmt.Errorf("failed to negotiate: %s", err)
}
raw, header, err := smb1AnonymousLogin(conn)
if err != nil {
return nil, nil, fmt.Errorf("failed to login with anonymous: %s", err)
}
_, err = getOSName(raw)
if err != nil {
return nil, nil, fmt.Errorf("failed to get OS name: %s", err)
}
//fmt.Println("OS:", osName)
header, err = treeConnectAndX(conn, address, header.UserID)
if err != nil {
return nil, nil, fmt.Errorf("failed to tree connect AndX: %s", err)
}
ok = true
return header, conn, nil
}
View on GitHub (pinned to 95cc12e753)
Solutions
- Confirm the port actually speaks SMB (banner/protocol detection) rather than assuming 445 is SMB
- Check whether the target supports SMB1; if it is SMB2-only, this SMB1-based exploit path will not work
- Inspect the wrapped smb1GetResponse error to distinguish timeout (retry) vs reset (target refusing SMB1)
- Retry with backoff; transient resets during mass scanning are common
Defensive patterns
Strategy: retry
Validate before calling
// Confirm SMB1 negotiation works on a throwaway connection first
func canNegotiateSMB1(address string) bool {
conn, err := net.DialTimeout("tcp", address, 10*time.Second)
if err != nil { return false }
defer conn.Close()
_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
return smbClientNegotiate(conn) == nil
} Type guard
func isNegotiateFailure(err error) bool {
return strings.HasPrefix(err.Error(), "failed to negotiate:")
} Try / catch
for attempt := 0; attempt < 3; attempt++ {
header, conn, err := smb1AnonymousConnectIPC(addr)
if err == nil { use(conn); return }
if !isNegotiateFailure(err) { return err } // only retry negotiate failures
time.Sleep(time.Duration(1<<attempt) * time.Second)
} Prevention
- Verify the port speaks SMB, not some other protocol, before SMB-level operations
- Accept that SMB2-only hosts can never pass this stage; exclude them
- Back off between retries to avoid tripping rate limiters
- Fresh connection per retry — a failed negotiate leaves the stream unusable
When it happens
Trigger: smbClientNegotiate's buf.WriteTo(conn) fails (peer reset the connection right after accept), or smb1GetResponse fails: NetBIOS read error/timeout, non-zero message type byte, response shorter than the 32-byte SMB header, short read, or unparseable header.
Common situations: Target is not an SMB service (some other daemon on 445 answering garbage); honeypots or proxies that accept TCP then close; SMB servers that immediately negotiate SMB2-only and drop SMB1 clients; rate-limiting devices resetting sessions.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- failed to tree connect AndX: %s
- smb_probe_failed: %w
- ms17010_connection_error: %w
- ms17010_send_protocol_error: %w
- ms17010_smbv1_unsupported
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/6273ab9061c5339a.
Report an issue: GitHub.