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

  1. Confirm the port actually speaks SMB (banner/protocol detection) rather than assuming 445 is SMB
  2. Check whether the target supports SMB1; if it is SMB2-only, this SMB1-based exploit path will not work
  3. Inspect the wrapped smb1GetResponse error to distinguish timeout (retry) vs reset (target refusing SMB1)
  4. 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

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


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/6273ab9061c5339a. Report an issue: GitHub.