shadow1ng/fscan · error

ReadConnectResponse %v

Error message

ReadConnectResponse %v

What it means

recvConnectResponse is the 'data' handler waiting for the server's MCS Connect Response. It calls ReadConnectResponse on the raw bytes; any parse failure (bad application tag, bad enumerated result, bad BER tags, invalid octet string tag) is re-wrapped as 'ReadConnectResponse %v' and emitted as an error. It means the server's MCS Connect Response could not be decoded.

Source

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

	dataBuff := &bytes.Buffer{}
	ber.WriteApplicationTag(uint8(MCS_TYPE_CONNECT_INITIAL), len(connectInitialBerEncoded), dataBuff)
	dataBuff.Write(connectInitialBerEncoded)

	_, err := c.transport.Write(dataBuff.Bytes())
	if err != nil {
		c.Emit("error", errors.New(fmt.Sprintf("mcs sendConnectInitial write error %v", err)))
		return
	}
	glog.Debug("mcs wait for data event")
	c.transport.Once("data", c.recvConnectResponse)
}

func (c *MCSClient) recvConnectResponse(s []byte) {
	glog.Debug("mcs recvConnectResponse", hex.EncodeToString(s))
	cResp, err := ReadConnectResponse(bytes.NewReader(s))
	if err != nil {
		c.Emit("error", errors.New(fmt.Sprintf("ReadConnectResponse %v", err)))
		return
	}
	// record server gcc block
	serverSettings := gcc.ReadConferenceCreateResponse(cResp.userData)
	for _, v := range serverSettings {
		switch v.(type) {
		case *gcc.ServerSecurityData:
			c.serverSecurityData = v.(*gcc.ServerSecurityData)

		case *gcc.ServerCoreData:
			c.serverCoreData = v.(*gcc.ServerCoreData)

		case *gcc.ServerNetworkData:
			c.serverNetworkData = v.(*gcc.ServerNetworkData)

		default:
			err := errors.New(fmt.Sprintf("unhandle server gcc block %v", reflect.TypeOf(v)))
			glog.Error(err)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Check the hex dump logged at the top of recvConnectResponse: the first byte should indicate an MCS Connect Response (0x66<<2 pattern with BER application tag).
  2. Verify the peer is a genuine RDP server on the expected port.
  3. Check whether the server requires NLA and terminates the handshake early; handle security protocol negotiation before MCS.
  4. Add the wrapped cause (%v) inspection — the inner error names exactly which BER step failed.

Example fix

// before
cResp, err := ReadConnectResponse(bytes.NewReader(s))
if err != nil {
    c.Emit("error", errors.New(fmt.Sprintf("ReadConnectResponse %v", err)))
    return
}
// after
cResp, err := ReadConnectResponse(bytes.NewReader(s))
if err != nil {
    c.Emit("error", fmt.Errorf("ReadConnectResponse: %w", err))
    c.transport.Close()
    return
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the response prefix is an MCS Connect Response before full parse:
func isConnectResponse(b []byte) bool {
    return len(b) > 2 && (b[0]&0xfc)>>2 == 0x66>>0 // BER app tag 0x66 pattern
}

Try / catch

mcs.On("error", func(err error) {
    if strings.Contains(err.Error(), "ReadConnectResponse") {
        // log hex dump, verify server identity/protocol, retry
    }
})

Prevention

When it happens

Trigger: The once-registered transport 'data' handler recvConnectResponse receives bytes for which ReadConnectResponse returns an error — wrong application tag (not MCS_TYPE_CONNECT_RESPONSE 0x66), failed BER parsing, or truncated userData.

Common situations: Connecting to a non-RDP service that replies with garbage; the server rejects the connection with a Connect Response carrying a non-zero result encoded unexpectedly; TCP coalescing/fragmentation delivers partial frames; server sent a security-negotiation failure instead of the MCS response.

Related errors


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