shadow1ng/fscan · error

mssql: packet type changed in message

Error message

mssql: packet type changed in message

What it means

mssqlReadMessage assembles a TDS message from one or more packets; every packet of a message must carry the same packet type byte. If a continuation packet's type differs from the type recorded for the first packet, the stream violates the TDS framing rules and reading aborts with this error.

Solutions

  1. Confirm the peer is a real SQL Server speaking TDS on the expected port.
  2. Discard the connection and restart the handshake — the stream is desynchronized once framing is violated.
  3. Check for middleboxes/proxies multiplexing the TCP stream and connect directly.
  4. If parsing crafted input, note the parser correctly rejects it; treat it as untrusted and stop.
Defensive patterns

Strategy: try-catch

Try / catch

pktType, payload, err := mssqlReadMessage(conn)
if err != nil {
    if strings.Contains(err.Error(), "packet type changed") {
        conn.Close() // stream desynchronized; restart handshake or drop target
    }
}

Prevention

When it happens

Trigger: Reading a prelogin or login response where a multi-packet message (status EOM bit not set on the first packet) arrives whose subsequent packet header contains a different type byte than the first — a corrupted, interleaved, or non-TDS stream.

Common situations: Port serving a different protocol that happens to emit 8-byte-aligned garbage; a proxy interleaving responses from two connections; an intentional malicious server mixing packet types to break parsers.

Related errors


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

Appendix: source

Thrown at plugins/services/mssql_raw.go:433

	if _, err := w.Write(header); err != nil {
		return err
	}
	_, err := w.Write(payload)
	return err
}

func mssqlReadMessage(r io.Reader) (byte, []byte, error) {
	var packetType byte
	var payload []byte
	for {
		header := make([]byte, 8)
		if _, err := io.ReadFull(r, header); err != nil {
			return 0, nil, err
		}
		if packetType == 0 {
			packetType = header[0]
		} else if packetType != header[0] {
			return 0, nil, fmt.Errorf("mssql: packet type changed in message")
		}
		size := int(binary.BigEndian.Uint16(header[2:4]))
		if size < 8 {
			return 0, nil, fmt.Errorf("mssql: invalid packet size")
		}
		chunk := make([]byte, size-8)
		if _, err := io.ReadFull(r, chunk); err != nil {
			return 0, nil, err
		}
		if len(payload)+len(chunk) > maxTDSMessageSize {
			return 0, nil, fmt.Errorf("mssql: message too large")
		}
		payload = append(payload, chunk...)
		if header[1]&tdsStatusEOM != 0 {
			return packetType, payload, nil
		}
	}
}

View on GitHub (pinned to 95cc12e753)