shadow1ng/fscan · warning

netbios_smb_negotiate_send_failed: %w

Error message

netbios_smb_negotiate_send_failed: %w

What it means

This error occurs in queryNetBIOSSession when writing the SMB negotiate packet (smbNegotiate1) to a NetBIOS session service TCP connection on port 139 fails. The library wraps the underlying net.Conn.Write error with the i18n message 'netbios_smb_negotiate_send_failed'. It means the TCP connection was established (DialTCP succeeded) but broke before the first SMB packet could be delivered.

Source

Thrown at plugins/services/netbios.go:217

	_ = conn.SetDeadline(time.Now().Add(session.Config.ModuleTimeout()))

	// 发送SMB协商数据包
	smbNegotiate1 := []byte{
		0x00, 0x00, 0x00, 0x85, 0xFF, 0x53, 0x4D, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xC8,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4E, 0x45, 0x54, 0x57, 0x4F,
		0x52, 0x4B, 0x20, 0x50, 0x52, 0x4F, 0x47, 0x52, 0x41, 0x4D, 0x20, 0x31, 0x2E, 0x30, 0x00, 0x02,
		0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x31, 0x2E, 0x30, 0x00, 0x02, 0x57, 0x69, 0x6E, 0x64, 0x6F,
		0x77, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x70,
		0x73, 0x20, 0x33, 0x2E, 0x31, 0x61, 0x00, 0x02, 0x4C, 0x4D, 0x31, 0x2E, 0x32, 0x58, 0x30, 0x30,
		0x32, 0x00, 0x02, 0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x32, 0x2E, 0x31, 0x00, 0x02, 0x4E, 0x54,
		0x20, 0x4C, 0x4D, 0x20, 0x30, 0x2E, 0x31, 0x32, 0x00,
	}

	_, err = conn.Write(smbNegotiate1)
	if err != nil {
		return nil, fmt.Errorf("%s: %w", i18n.GetText("netbios_smb_negotiate_send_failed"), err)
	}

	response1 := make([]byte, 1024)
	_, err = conn.Read(response1)
	if err != nil {
		return nil, fmt.Errorf("%s: %w", i18n.GetText("netbios_smb_negotiate_read_failed"), err)
	}

	// 发送Session Setup请求
	smbSessionSetup := []byte{
		0x00, 0x00, 0x01, 0x0A, 0xFF, 0x53, 0x4D, 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0xC8,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
		0x00, 0x00, 0x40, 0x00, 0x0C, 0xFF, 0x00, 0x0A, 0x01, 0x04, 0x41, 0x32, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0xA0, 0xCF, 0x00, 0x60,
		0x48, 0x06, 0x06, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x02, 0xA0, 0x3E, 0x30, 0x3C, 0xA0, 0x0E, 0x30,
		0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0A, 0xA2, 0x2A, 0x04,
		0x28, 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x82, 0x08,
		0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Verify the target host actually speaks SMB on TCP 139 (nmap -p139 --script smb-os-discovery); if it doesn't, exclude it from scanning.
  2. Increase config.ModuleTimeout() so the SetDeadline does not expire during the write.
  3. Check for firewalls/IPS between scanner and host that reset SMB packets; whitelist the scanner IP.
  4. Inspect the wrapped %w error to distinguish i/o timeout vs connection reset and handle each case specifically.

Example fix

// before
conn, err := session.DialTCP(ctx, "tcp", target, session.Config.ModuleTimeout())
_, err = conn.Write(smbNegotiate1)

// after
conn, err := session.DialTCP(ctx, "tcp", target, 2*session.Config.ModuleTimeout())
if err != nil { return nil, err }
if n, werr := conn.Write(smbNegotiate1); werr != nil {
    var nerr net.Error
    if errors.As(werr, &nerr) && nerr.Timeout() {
        return nil, fmt.Errorf("smb negotiate timed out after %v: %w", session.Config.ModuleTimeout(), werr)
    }
    return nil, fmt.Errorf("%s: %w", i18n.GetText("netbios_smb_negotiate_send_failed"), werr)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: check TCP 139 reachability and a sane timeout before scanning
if config.ModuleTimeout() < 2*time.Second {
    return fmt.Errorf("module timeout %v too short for SMB negotiate", config.ModuleTimeout())
}
conn, err := net.DialTimeout("tcp", host+":139", config.ModuleTimeout())
if err != nil {
    return fmt.Errorf("host %s not reachable on TCP 139: %w", host, err)
}
_ = conn.Close()

Type guard

func isNetError(err error) (net.Error, bool) {
    var nerr net.Error
    if errors.As(err, &nerr) {
        return nerr, true
    }
    return nil, false
}

Try / catch

info, err := plugin.Scan(ctx, host, session)
if err != nil {
    var nerr net.Error
    if errors.As(err, &nerr) && nerr.Timeout() {
        log.Printf("skip %s: negotiate send timeout", host)
        return nil // treat as no NetBIOS service
    }
    if errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.EPIPE) {
        log.Printf("skip %s: connection reset during negotiate", host)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling Scan -> queryNetBIOSSession against a host where TCP 139 accepts the connection but the write fails: connection reset by peer immediately after accept, connection closed by the remote host mid-write, or the deadline set via SetDeadline(ModuleTimeout) expiring during the write.

Common situations: Windows hosts with SMB disabled but NetBIOS port-filtering middleware that accepts and drops connections; firewalls/IPS that RST SMB traffic; host crashed or rebooted between dial and write; extremely short ModuleTimeout values causing i/o timeout; scanning hosts that only expose UDP 137 but have a half-open TCP 139 listener.

Related errors


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