shadow1ng/fscan · error

ms17010_send_protocol_error: %w

Error message

ms17010_send_protocol_error: %w

What it means

During SMB negotiation, checkMS17010VulnerabilityAt writes the negotiateProtocolRequest packet and wraps any conn.Write failure as "ms17010_send_protocol_error". The probe cannot deliver the SMBv1 negotiation, so the vulnerability check aborts with this error propagated to Scan/Exploit.

Source

Thrown at plugins/services/ms17010.go:306

// checkMS17010Vulnerability 检测MS17-010漏洞 (从原始MS17010.go复制和适配)
func (p *MS17010Plugin) checkMS17010Vulnerability(ctx context.Context, ip string, session *common.ScanSession) (bool, string, bool, error) {
	return p.checkMS17010VulnerabilityAt(ctx, net.JoinHostPort(ip, "445"), session)
}

func (p *MS17010Plugin) checkMS17010VulnerabilityAt(ctx context.Context, address string, session *common.ScanSession) (bool, string, bool, error) {
	conn, err := session.DialTCP(ctx, "tcp", address, session.Config.ModuleTimeout())
	if err != nil {
		return false, "", false, fmt.Errorf("%s: %w", i18n.GetText("ms17010_connection_error"), err)
	}
	defer func() { _ = conn.Close() }()

	if err = conn.SetDeadline(time.Now().Add(session.Config.ModuleTimeout())); err != nil {
		return false, "", false, fmt.Errorf("%s: %w", i18n.GetText("ms17010_set_timeout_error"), err)
	}

	// SMB协议协商
	if _, err = conn.Write(negotiateProtocolRequest); err != nil {
		return false, "", false, fmt.Errorf("%s: %w", i18n.GetText("ms17010_send_protocol_error"), err)
	}

	reply := make([]byte, 1024)
	n, readErr := conn.Read(reply)
	if readErr != nil || n < 36 {
		// 连接被关闭或响应不完整,通常表示目标不支持SMBv1
		return false, "", false, fmt.Errorf("%s", i18n.GetText("ms17010_smbv1_unsupported"))
	}

	if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
		return false, "", false, fmt.Errorf("%s", i18n.GetText("ms17010_smbv1_rejected"))
	}

	// 建立会话
	if _, err = conn.Write(sessionSetupRequest); err != nil {
		return false, "", false, fmt.Errorf("%s: %w", i18n.GetText("ms17010_send_session_error"), err)
	}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Unwrap the error: 'broken pipe'/'connection reset by peer' indicates the target or a middlebox killed the connection — treat as 'SMB not reachable' rather than a bug.
  2. Retry once after a short delay; transient resets are common on noisy networks.
  3. Verify with nmap -p445 --script smb-protocols that the target accepts SMB negotiation at all.
  4. Increase ModuleTimeout if deadline-expired errors appear under load.

Example fix

// before: hard failure on transient write error
res := plugin.Scan(ctx, host, session)
if res.Error != nil { log.Fatal(res.Error) }
// after: tolerate transient SMB send failures
if res.Error != nil && strings.Contains(res.Error.Error(), "protocol") {
    log.Printf("SMB negotiation failed for %s, host may block SMBv1", host.Host)
}
Defensive patterns

Strategy: retry

Try / catch

if err != nil {
    if errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) {
        return fmt.Errorf("target dropped SMB negotiation, treating as unreachable")
    }
    return err
}

Prevention

When it happens

Trigger: conn.Write(negotiateProtocolRequest) fails because the peer closed/reset the connection right after connect, the network dropped mid-session, or the context deadline expired killing the conn.

Common situations: Firewalls/IPS that accept the TCP handshake then RST the SMB payload, targets rejecting SMBv1 traffic immediately, or unstable Wi-Fi/VPN links during the scan.

Related errors


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