shadow1ng/fscan · error

Bad integer tag

Error message

Bad integer tag

What it means

ReadInteger parses a BER INTEGER. It first validates the universal tag byte equals TAG_INTEGER; a mismatch means the stream does not contain an integer where one is expected, so this error is returned. This typically indicates a malformed or misaligned CONNECT_RESPONSE or domain parameters blob.

Source

Thrown at libs/grdp/protocol/t125/ber/ber.go:104

		}
	} else {
		ret = int(size)
	}
	return ret, nil
}

func WriteLength(size int, w io.Writer) {
	if size > 0x7f {
		core.WriteUInt8(0x82, w)
		core.WriteUInt16BE(uint16(size), w)
	} else {
		core.WriteUInt8(uint8(size), w)
	}
}

func ReadInteger(r io.Reader) (int, error) {
	if !ReadUniversalTag(TAG_INTEGER, false, r) {
		return 0, errors.New("Bad integer tag")
	}
	size, _ := ReadLength(r)
	switch size {
	case 1:
		num, _ := core.ReadUInt8(r)
		return int(num), nil
	case 2:
		num, _ := core.ReadUint16BE(r)
		return int(num), nil
	case 3:
		integer1, _ := core.ReadUInt8(r)
		integer2, _ := core.ReadUint16BE(r)
		return int(integer2) + (int(integer1) << 16), nil
	case 4:
		num, _ := core.ReadUInt32BE(r)
		return int(num), nil
	default:
		return 0, errors.New("wrong size")

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Capture the raw X.224/T.125 exchange in Wireshark and compare the CONNECT_RESPONSE layout to the T.125 spec
  2. Verify earlier fields parsed the correct byte counts — a desync upstream makes this tag read garbage
  3. Confirm the target host/port actually runs an RDP server
  4. Update grdp; server encoder variants may place fields differently than this parser assumes

Example fix

// before
if !ReadUniversalTag(TAG_INTEGER, false, r) {
    return 0, errors.New("Bad integer tag")
}

// after
if !ReadUniversalTag(TAG_INTEGER, false, r) {
    return 0, fmt.Errorf("Bad integer tag: expected INTEGER (0x02), got 0x%02X", lastReadByte)
}
Defensive patterns

Strategy: validation

Validate before calling

// confirm the byte is an INTEGER tag before calling ReadInteger
if buf[pos] != 0x02 {
    return fmt.Errorf("not an INTEGER tag at offset %d: 0x%02X", pos, buf[pos])
}

Try / catch

n, err := ber.ReadInteger(r)
if err != nil {
    if strings.Contains(err.Error(), "Bad integer tag") {
        // stream is not a well-formed T.125 response; abort handshake cleanly
        return ErrNotRdpServer
    }
    return err
}

Prevention

When it happens

Trigger: ReadDomainParameters or ReadConnectResponse calling ReadInteger when the byte at the integer field position is not the TAG_INTEGER universal tag.

Common situations: Connecting to a service that is not RDP; protocol desync from mismatched negotiation flags shifting field boundaries; proxies or middleboxes altering the byte stream.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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