shadow1ng/fscan · error

ReadApplicationTag invalid data

Error message

ReadApplicationTag invalid data

What it means

ReadApplicationTag parses a BER application-class tag. When the requested tag number exceeds 30 it needs the multi-byte long tag form, so the first byte must equal (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK (0x6F). Any other byte means the data is not a valid high-numbered application tag.

Source

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

	WriteLength(len(str), w)
	core.WriteBytes([]byte(str), w)
}

func WriteBoolean(b bool, w io.Writer) {
	bb := uint8(0)
	if b {
		bb = uint8(0xff)
	}
	WriteUniversalTag(TAG_BOOLEAN, false, w)
	WriteLength(1, w)
	core.WriteUInt8(bb, w)
}

func ReadApplicationTag(tag uint8, r io.Reader) (int, error) {
	bb, _ := core.ReadUInt8(r)
	if tag > 30 {
		if bb != (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK {
			return 0, errors.New("ReadApplicationTag invalid data")
		}
		bb, _ := core.ReadUInt8(r)
		if bb != tag {
			return 0, errors.New("ReadApplicationTag bad tag")
		}
	} else {
		if bb != (CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag) {
			return 0, errors.New("ReadApplicationTag invalid data2")
		}
	}
	return ReadLength(r)
}

func WriteApplicationTag(tag uint8, size int, w io.Writer) {
	if tag > 30 {
		core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|TAG_MASK, w)
		core.WriteUInt8(tag, w)
		WriteLength(size, w)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Capture and hex-dump the CONNECT_RESPONSE; check the first byte of the application tag field against 0x6F
  2. Confirm the target is a genuine RDP server and the port is not answered by another service
  3. Trace upstream parsing to find where the byte alignment went wrong and fix that parser
  4. Check whether the server sent a negotiation failure PDU instead of the expected response

Example fix

// before
if bb != (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK {
    return 0, errors.New("ReadApplicationTag invalid data")
}

// after
if bb != (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK {
    return 0, fmt.Errorf("ReadApplicationTag invalid data: expected 0x6F, got 0x%02X", bb)
}
Defensive patterns

Strategy: validation

Validate before calling

// verify the application tag byte before calling ReadApplicationTag
expected := byte((ber.CLASS_APPL | ber.PC_CONSTRUCT) | ber.TAG_MASK)
if buf[pos] != expected {
    return fmt.Errorf("no long-form application tag at offset %d: got 0x%02X, want 0x%02X", pos, buf[pos], expected)
}

Try / catch

n, err := ber.ReadApplicationTag(101, r)
if err != nil {
    if strings.Contains(err.Error(), "invalid data") {
        return fmt.Errorf("response is not the expected T.125 CONNECT_RESPONSE: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: ReadConnectResponse calling ReadApplicationTag with tag > 30 (e.g. tag 101 for the T.125 CONNECT_RESPONSE) when the first stream byte is not 0x6F — the field is misaligned or absent.

Common situations: Non-RDP services answering on 3389; desync from mismatched X.224 negotiation; TLS interception or proxy altering the response bytes; servers answering with an error PDU instead of CONNECT_RESPONSE where the application tag is expected.

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/e07545922c6d1541. Report an issue: GitHub.