{"record":{"id":"bfaf8d4cac9ea588","repo":"shadow1ng/fscan","slug":"node-rdp-protocol-t125-mcs-wait-channel-join-confi","errorCode":null,"errorMessage":"NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM","messagePattern":"NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/grdp/protocol/t125/mcs.go","lineNumber":497,"sourceCode":"\tif err != nil {\n\t\tc.Emit(\"error\", errors.New(fmt.Sprintf(\"mcs recvData get data error %v\", err)))\n\t\treturn\n\t}\n\tglog.Debugf(\"mcs emit channel<%s>:%v\", channelName, left)\n\tc.Emit(\"sec\", channelName, left)\n}\n\nfunc (c *MCSClient) recvChannelJoinConfirm(s []byte) {\n\tglog.Debug(\"mcs recvChannelJoinConfirm\", hex.EncodeToString(s))\n\tr := bytes.NewReader(s)\n\toption, err := core.ReadUInt8(r)\n\tif err != nil {\n\t\tc.Emit(\"error\", err)\n\t\treturn\n\t}\n\n\tif !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM\"))\n\t\treturn\n\t}\n\n\tconfirm, _ := per.ReadEnumerates(r)\n\tuserId, _ := per.ReadInteger16(r)\n\tuserId += MCS_USERCHANNEL_BASE\n\n\tif c.userId != userId {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID\"))\n\t\treturn\n\t}\n\n\tchannelId, _ := per.ReadInteger16(r)\n\tif (confirm != 0) && (channelId == uint16(MCS_GLOBAL_CHANNEL_ID) || channelId == c.userId) {\n\t\tc.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL\"))\n\t\treturn\n\t}\n\tglog.Debug(\"Confirm channelId:\", channelId)","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/t125/mcs.go#L479-L515","documentation":"After sending MCS Channel Join Requests, the client reads the Channel Join Confirm PDU and validates its header via readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM). If the PDU received is not a Channel Join Confirm (wrong type or malformed header), the library emits this sentinel error and aborts the join sequence. It is a protocol-state error: the server responded out of the expected T.125 state machine order.","triggerScenarios":"recvChannelJoinConfirm reads a PDU whose header does not match CHANNEL_JOIN_CONFIRM — e.g. the server sent a Disconnect Provider Ultimatum, a different MCS PDU type, or garbage bytes after the user channel join request.","commonSituations":"Connecting to a non-standard RDP server or gateway that interleaves MCS PDUs differently; server rejected the connection earlier and sent a disconnect PDU; desynced stream due to a preceding parsing bug leaving bytes in the buffer.","solutions":["Log the actual PDU type received to identify what the server sent instead of the join confirm.","Retry the connection once — transient server-side disconnects are common under load.","Verify server RDP protocol support; older/proprietary servers may not follow the standard MCS join flow.","Check that no earlier parsing step (X224/SEC) left unread bytes causing stream desync."],"exampleFix":"// before\nif !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {\n    c.Emit(\"error\", errors.New(\"NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM\"))\n    return\n}\n// after\nif !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {\n    c.Emit(\"error\", fmt.Errorf(\"mcs: expected CHANNEL_JOIN_CONFIRM, got pdu type %d\", option))\n    return\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"c.On(\"error\", func(err error) {\n    if strings.Contains(err.Error(), \"WAIT_CHANNEL_JOIN_CONFIRM\") {\n        log.Println(\"unexpected MCS PDU during join; retrying handshake\")\n        retryConnect(1)\n    }\n})","preventionTips":["Test against a standard RDP server before deploying to exotic targets","Log the received PDU type to spot protocol desync early","Reuse a fresh client object per connection to avoid stale stream state"],"tags":["rdp","mcs","protocol-state","handshake"],"backgroundTag":"unexpected-response-shape","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}