shadow1ng/fscan · error

mssql: invalid us varchar size

Error message

mssql: invalid us varchar size

What it means

mssqlReadUSVarChar parses a TDS USHORT-length (UCS-2/UTF-16) string from a raw packet payload. After reading the 2-byte character count it computes the byte size as chars*2 and verifies those bytes exist in the payload. If they do not fit within the remaining buffer, it refuses to slice out of bounds and returns this error.

Source

Thrown at plugins/services/mssql_raw.go:404

		return pos, fmt.Errorf("mssql: truncated token")
	}
	size := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
	next := pos + 2 + size
	if next > len(payload) {
		return pos, fmt.Errorf("mssql: invalid token size")
	}
	return next, nil
}

func mssqlReadUSVarChar(payload []byte, pos int) (string, int, error) {
	if pos+2 > len(payload) {
		return "", pos, fmt.Errorf("mssql: truncated us varchar")
	}
	chars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
	pos += 2
	size := chars * 2
	if pos+size > len(payload) {
		return "", pos, fmt.Errorf("mssql: invalid us varchar size")
	}
	return mssqlDecodeUCS2(payload[pos : pos+size]), pos + size, nil
}

func mssqlWritePacket(w io.Writer, packetType byte, payload []byte) error {
	if len(payload)+8 > 0xffff {
		return fmt.Errorf("mssql: packet too large")
	}
	header := []byte{packetType, tdsStatusEOM, 0, 0, 0, 0, 1, 0}
	binary.BigEndian.PutUint16(header[2:4], uint16(len(payload)+8))
	if _, err := w.Write(header); err != nil {
		return err
	}
	_, err := w.Write(payload)
	return err
}

func mssqlReadMessage(r io.Reader) (byte, []byte, error) {

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Verify the server is a genuine SQL Server speaking correct TDS; a wrong service on the port yields garbage payloads.
  2. Treat the stream as untrusted: this error indicates corrupt input — drop the connection and re-connect if transient.
  3. If parsing custom TDS tokens, confirm the token length field was honored before calling mssqlReadUSVarChar (offset advanced by the declared token size).
  4. Update the plugin/parser version — earlier token parsers may mis-offset subsequent usvarchar reads.

Example fix

// before
chars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
pos += 2
size := chars * 2
if pos+size > len(payload) {
    return "", pos, fmt.Errorf("mssql: invalid us varchar size")
}
// after
chars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
pos += 2
size := chars * 2
if size < 0 || pos+size > len(payload) {
    return "", pos, fmt.Errorf("mssql: invalid us varchar size (need %d bytes, have %d)", size, len(payload)-pos)
}
Defensive patterns

Strategy: validation

Validate before calling

func canReadUSVarChar(payload []byte, pos int) bool {
    if pos+2 > len(payload) {
        return false
    }
    chars := int(binary.LittleEndian.Uint16(payload[pos : pos+2]))
    return pos+2+chars*2 <= len(payload)
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "invalid us varchar size") {
        // malformed TDS token: drop connection, mark target untrusted
    }
}

Prevention

When it happens

Trigger: Parsing a TDS token (e.g. an ERROR token via mssqlParseErrorToken, or mssqlSkipUSVarError) whose embedded usvarchar length field claims more bytes than the packet actually contains — typically a malformed, truncated, or maliciously crafted server response.

Common situations: Talking to a non-MSSQL or middleware service that emits broken TDS streams; a packet truncated by a proxy or NAT; fuzzing/pen-testing a fake SQL Server that returns malformed ERROR tokens.

Related errors


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