shadow1ng/fscan · error
mssql: empty prelogin response
Error message
mssql: empty prelogin response
What it means
The prelogin response arrived as a valid REPLY packet but contained zero payload bytes. A correct prelogin response must include an option table plus values; an empty body means the server sent a degenerate response.
Source
Thrown at plugins/services/mssql_raw.go:157
}
payload.WriteByte(tdsPreloginTerminator)
for _, key := range keys {
payload.Write(fields[byte(key)])
}
return mssqlWritePacket(w, tdsPacketPrelogin, payload.Bytes())
}
func mssqlReadPrelogin(r io.Reader) error {
packetType, payload, err := mssqlReadMessage(r)
if err != nil {
return err
}
if packetType != tdsPacketReply {
return fmt.Errorf("mssql: invalid prelogin response packet type %d", packetType)
}
if len(payload) == 0 {
return fmt.Errorf("mssql: empty prelogin response")
}
fields, err := mssqlParsePreloginFields(payload)
if err != nil {
return err
}
if _, ok := fields[tdsPreloginEncryption]; !ok {
return fmt.Errorf("mssql: prelogin response missing encryption field")
}
return nil
}
func mssqlParsePreloginFields(payload []byte) (map[byte][]byte, error) {
fields := make(map[byte][]byte)
for pos := 0; ; pos += 5 {
if pos >= len(payload) {
return nil, fmt.Errorf("mssql: invalid prelogin option table")
}View on GitHub (pinned to 95cc12e753)
Solutions
- Verify the target is a genuine SQL Server endpoint (try sqlcmd or go-mssqldb against the same host:port).
- Check firewall/IDS devices that may truncate packets.
- Retry the connection; transient mid-handshake resets produce this intermittently.
- Inspect network logs for connection resets from the server.
Defensive patterns
Strategy: retry
Validate before calling
// Preflight reachability so empty responses are not confused with unreachable hosts:
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, fmt.Sprint(port)), timeout)
if err != nil { return fmt.Errorf("unreachable: %w", err) }
_ = conn.Close() Try / catch
var res *mssqlRawResult
var err error
for i := 0; i < 2; i++ {
res, err = mssqlRawLogin(ctx, host, port, user, pass, timeout)
if err == nil || !strings.Contains(err.Error(), "empty prelogin response") {
break
}
time.Sleep(200 * time.Millisecond)
} Prevention
- Retry once on empty responses — mid-handshake resets are often transient.
- Check firewall/IDS devices that may strip TCP payloads.
- Validate the endpoint with sqlcmd before writing raw probes.
When it happens
Trigger: mssqlReadPrelogin reads packet type 4 with an empty payload after sending the prelogin packet (payload length exactly 8 in the TDS header).
Common situations: Server-side connection teardown mid-handshake; middleware or firewall stripping the body; a honeypot or non-MSSQL service on the port returning an empty TDS-shaped packet.
Related errors
- mssql: invalid prelogin response packet type %d
- mssql: prelogin response missing encryption field
- mssql: invalid prelogin option table
- mssql: truncated prelogin option
- mssql: invalid prelogin option bounds
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/3becd08a5abbe8d7.
Report an issue: GitHub.