shadow1ng/fscan · error

invalid expected BER tag

Error message

invalid expected BER tag

What it means

ReadConnectResponse, after parsing result, calledConnectId and DomainParameters, expects a BER OCTET STRING universal tag holding the userData (GCC blocks). If ReadUniversalTag(TAG_OCTET_STRING, constructed=false) fails, the tail of the MCS Connect Response is not the expected octet string. The response is malformed or truncated at that point.

Source

Thrown at libs/grdp/protocol/t125/mcs.go:199

func ReadConnectResponse(r io.Reader) (*ConnectResponse, error) {
	c := &ConnectResponse{}
	var err error
	_, err = ber.ReadApplicationTag(MCS_TYPE_CONNECT_RESPONSE, r)
	if err != nil {
		return nil, err
	}
	c.result, err = ber.ReadEnumerated(r)
	if err != nil {
		return nil, err
	}

	c.calledConnectId, err = ber.ReadInteger(r)
	c.domainParameters, err = ReadDomainParameters(r)
	if err != nil {
		return nil, err
	}
	if !ber.ReadUniversalTag(ber.TAG_OCTET_STRING, false, r) {
		return nil, errors.New("invalid expected BER tag")
	}
	dataLen, _ := ber.ReadLength(r)
	c.userData, err = core.ReadBytes(dataLen, r)
	return c, err
}

type MCSChannelInfo struct {
	ID   uint16
	Name string
}

type MCS struct {
	emission.Emitter
	transport  core.Transport
	recvOpCode MCSDomainPDU
	sendOpCode MCSDomainPDU
	channels   []MCSChannelInfo
}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Log the hex dump of the full response and verify the expected tag byte 0x04 at that offset.
  2. Ensure the transport delivers the complete MCS Connect Response (length-prefixed) before invoking recvConnectResponse.
  3. Check the DomainParameters parse consumed exactly the encoded length (ReadLength result is discarded in ReadDomainParameters — a mismatch desynchronizes parsing).
  4. Include the actual byte value in the error for faster diagnosis.

Example fix

// before
if !ber.ReadUniversalTag(ber.TAG_OCTET_STRING, false, r) {
    return nil, errors.New("invalid expected BER tag")
}
// after
if !ber.ReadUniversalTag(ber.TAG_OCTET_STRING, false, r) {
    return nil, fmt.Errorf("invalid expected BER tag: want OCTET_STRING(0x04)")
}
Defensive patterns

Strategy: try-catch

Validate before calling

// After DomainParameters, verify the next tag is a primitive OCTET STRING:
if len(buf) > 0 && buf[pos] != 0x04 {
    return errors.New("Connect Response userData tag is not OCTET STRING")
}

Try / catch

mcs.On("error", func(err error) {
    if strings.Contains(err.Error(), "invalid expected BER tag") {
        // response malformed/truncated — reconnect or inspect raw dump
    }
})

Prevention

When it happens

Trigger: Parsing a server MCS Connect Response where, after DomainParameters, the next byte is not a primitive OCTET STRING tag (0x04) — e.g. the response was truncated, contains a different encoding, or the reader was already misaligned.

Common situations: Server sends a Connect Response with an empty or differently encoded userData section; TCP fragmentation/partial reads deliver an incomplete buffer to ReadConnectResponse; non-RDP service on the port; earlier BER parse consumed wrong lengths shifting the tag position.

Related errors


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