shadow1ng/fscan · error

bad BER tags

Error message

bad BER tags

What it means

ReadDomainParameters expects the server's MCS Connect Response to contain DomainParameters encoded as a BER SEQUENCE (0x30 universal tag, constructed). If ber.ReadUniversalTag(TAG_SEQUENCE, constructed=true) fails, the byte stream is not the expected BER structure. This means the MCS layer payload is malformed or out of sync.

Source

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

		numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion}
}

func (d *DomainParameters) BER() []byte {
	buff := &bytes.Buffer{}
	ber.WriteInteger(d.MaxChannelIds, buff)
	ber.WriteInteger(d.MaxUserIds, buff)
	ber.WriteInteger(d.MaxTokenIds, buff)
	ber.WriteInteger(1, buff)
	ber.WriteInteger(0, buff)
	ber.WriteInteger(1, buff)
	ber.WriteInteger(d.MaxMCSPDUsize, buff)
	ber.WriteInteger(2, buff)
	return buff.Bytes()
}

func ReadDomainParameters(r io.Reader) (*DomainParameters, error) {
	if !ber.ReadUniversalTag(ber.TAG_SEQUENCE, true, r) {
		return nil, errors.New("bad BER tags")
	}
	d := &DomainParameters{}
	ber.ReadLength(r)

	d.MaxChannelIds, _ = ber.ReadInteger(r)
	d.MaxUserIds, _ = ber.ReadInteger(r)
	d.MaxTokenIds, _ = ber.ReadInteger(r)
	ber.ReadInteger(r)
	ber.ReadInteger(r)
	ber.ReadInteger(r)
	d.MaxMCSPDUsize, _ = ber.ReadInteger(r)
	ber.ReadInteger(r)
	return d, nil
}

/**
 * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
 * @param userData {Buffer}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Confirm the target speaks RDP on that port and that security negotiation (e.g. NLA/CredSSP) does not divert the handshake before MCS.
  2. Hex-dump the received buffer (mcs.go already logs it) and verify the byte at the failure offset is 0x30.
  3. Check earlier parsing steps (ReadApplicationTag, ReadEnumerated, ReadInteger) consumed the exact byte counts; a wrong length earlier desynchronizes the reader.
  4. Return the underlying byte/tag value in the error message to ease diagnosis.

Example fix

// before
if !ber.ReadUniversalTag(ber.TAG_SEQUENCE, true, r) {
    return nil, errors.New("bad BER tags")
}
// after
b, _ := core.PeekByte(r)
if !ber.ReadUniversalTag(ber.TAG_SEQUENCE, true, r) {
    return nil, fmt.Errorf("bad BER tags: expected SEQUENCE(0x30), got 0x%02x", b)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Peek the first byte of the response before parsing MCS layers:
func looksLikeBERSequence(b []byte) bool { return len(b) > 0 && b[0] == 0x30 }

Try / catch

mcs.On("error", func(err error) {
    if strings.Contains(err.Error(), "bad BER tags") {
        // peer is not speaking RDP/T.125 — abort or retry against correct host/port
    }
})

Prevention

When it happens

Trigger: Called from ReadConnectResponse when parsing the server's MCS Connect Response: the first universal tag after result and calledConnectId is not a constructed SEQUENCE, i.e. the server response bytes deviate from T.125 BER encoding.

Common situations: The peer is not an RDP server (wrong port, HTTP banner server); a middlebox/proxy rewrites the response; a previous packet framed incorrectly so the reader is misaligned; servers that negotiate NLA and never send a plain MCS Connect Response at this point.

Related errors


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