shadow1ng/fscan · error

failed to parse SMB1 response header: %s

Error message

failed to parse SMB1 response header: %s

What it means

smb1GetResponse reads the fixed-size SMB1 header from the connection and parses it into an smbHeader struct with binary.Read. If the bytes on the wire do not fit the smbHeader layout (connection closed early, non-SMB response, or truncated read), the function returns this wrapped error. It is a low-level protocol parse failure inside the MS17-010 (EternalBlue) exploit plugin.

Source

Thrown at plugins/services/ms17010_exp.go:217

	copy(sizeBuf[1:], buf[1:])
	size := int(binary.BigEndian.Uint32(sizeBuf))
	// 畸形响应(size < SMB 头长度)会导致后续 buf[:smbHeaderSize] 越界 panic
	if size < smbHeaderSize {
		return nil, nil, fmt.Errorf("SMB1 response too short: %d bytes", size)
	}
	// SMB
	buf = make([]byte, size)
	_, err = io.ReadFull(conn, buf)
	if err != nil {
		const format = "failed to get SMB1 response about header: %s"
		return nil, nil, fmt.Errorf(format, err)
	}
	smbHeader := smbHeader{}
	reader := bytes.NewReader(buf[:smbHeaderSize])
	err = binary.Read(reader, binary.LittleEndian, &smbHeader)
	if err != nil {
		const format = "failed to parse SMB1 response header: %s"
		return nil, nil, fmt.Errorf(format, err)
	}
	return buf, &smbHeader, nil
}

func smbClientNegotiate(conn net.Conn) error {
	buf := bytes.Buffer{}

	// --------NetBIOS Session Service--------

	// message type
	buf.WriteByte(0x00)
	// length
	buf.Write([]byte{0x00, 0x00, 0x54})

	// --------Server Message Block Protocol--------

	// server_component: .SMB
	buf.Write([]byte{0xFF, 0x53, 0x4D, 0x42})

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Verify the target actually supports SMB1 (nmblookup/nmap smb-protocols) before running the exploit
  2. Check that port 445 is reachable and not proxied by a non-SMB service
  3. Retry the scan; transient truncation of the response stream causes spurious parse failures
  4. If auditing code, confirm the read loop fills the full smbHeaderSize buffer before binary.Read

Example fix

// before
buf := make([]byte, smbHeaderSize)
io.ReadFull(conn, buf) // may return short data ignored
// after
if _, err := io.ReadFull(conn, buf); err != nil {
    return nil, nil, fmt.Errorf("short SMB1 header read: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// probe SMB1 before running the exploit
func supportsSMB1(host string, port int) bool {
    conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 5*time.Second)
    if err != nil { return false }
    defer conn.Close()
    conn.Write(makeSMB1NegotiateProbe())
    buf := make([]byte, smbHeaderSize)
    _, err = io.ReadFull(conn, buf)
    return err == nil
}

Type guard

func isSMBHeader(buf []byte) bool {
    return len(buf) >= smbHeaderSize && binary.LittleEndian.Uint32(buf[0:4]) == smbMagic
}

Try / catch

buf, hdr, err := smb1GetResponse(conn)
if err != nil {
    var nerr net.Error
    if errors.As(err, &nerr) && nerr.Timeout() {
        // retry once with longer deadline
    }
    return fmt.Errorf("smb1 response unavailable: %w", err)
}

Prevention

When it happens

Trigger: Calling any of exploit, smbClientNegotiate, smb1AnonymousLogin, treeConnectAndX, smb1LargeBuffer, or sendNTTrans against a target whose reply is not a valid SMB1 header — e.g. the host closed the TCP connection before smbHeaderSize bytes arrived, a non-Windows service answered on port 445, or a middlebox reset the stream mid-response.

Common situations: Scanning a host that speaks SMB2/SMB3 only (SMB1 disabled on modern Windows), port 445 mapped to a honeypot or proxy, or flaky network links that truncate the read.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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