{"record":{"id":"d9ba62d5cce017bd","repo":"shadow1ng/fscan","slug":"enumerate-size-is-wrong-get-v-expect-1","errorCode":null,"errorMessage":"enumerate size is wrong, get %v, expect 1","messagePattern":"enumerate size is wrong, get (.+?), expect 1","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/grdp/protocol/t125/ber/ber.go","lineNumber":53,"sourceCode":")\n\nfunc berPC(pc bool) uint8 {\n\tif pc {\n\t\treturn PC_CONSTRUCT\n\t}\n\treturn PC_PRIMITIVE\n}\n\nfunc ReadEnumerated(r io.Reader) (uint8, error) {\n\tif !ReadUniversalTag(TAG_ENUMERATED, false, r) {\n\t\treturn 0, errors.New(\"invalid ber tag\")\n\t}\n\tlength, err := ReadLength(r)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif length != 1 {\n\t\treturn 0, errors.New(fmt.Sprintf(\"enumerate size is wrong, get %v, expect 1\", length))\n\t}\n\treturn core.ReadUInt8(r)\n}\n\nfunc ReadUniversalTag(tag uint8, pc bool, r io.Reader) bool {\n\tbb, _ := core.ReadUInt8(r)\n\treturn bb == (CLASS_UNIV|berPC(pc))|(TAG_MASK&tag)\n}\n\nfunc WriteUniversalTag(tag uint8, pc bool, w io.Writer) {\n\tcore.WriteUInt8((CLASS_UNIV|berPC(pc))|(TAG_MASK&tag), w)\n}\n\nfunc ReadLength(r io.Reader) (int, error) {\n\tret := 0\n\tsize, _ := core.ReadUInt8(r)\n\tif size&0x80 > 0 {\n\t\tsize = size &^ 0x80","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/t125/ber/ber.go#L35-L71","documentation":"After the ENUMERATED tag byte validates, ReadEnumerated reads the BER length. BER ENUMERATED used here must carry exactly one byte of content; any other length means the field is malformed, so the error reports the actual length versus the expected 1.","triggerScenarios":"ReadConnectResponse -> ReadEnumerated when ReadLength returns a value other than 1 (0, 2, or more) for the enumerated field — a malformed or nonstandard CONNECT_RESPONSE.","commonSituations":"Unusual server implementations encoding the enumerated domain selector with a non-1-byte length; corrupted or truncated responses from flaky networks; protocol desync from earlier skipped bytes.","solutions":["Capture the server's CONNECT_RESPONSE and verify the enumerated (requestedProtocols/domainSelector) encoding uses 1 content byte","Check for stream desync — an earlier parse consuming wrong byte counts shifts lengths; fix the earlier parser","If the server genuinely sends a different length, extend ReadEnumerated to decode variable-length enumerated values","Retry the connection; transient truncation from network issues can produce bogus lengths"],"exampleFix":"// before\nif length != 1 {\n    return 0, errors.New(fmt.Sprintf(\"enumerate size is wrong, get %v, expect 1\", length))\n}\n\n// after\nif length != 1 {\n    return 0, fmt.Errorf(\"enumerate size is wrong, get %v, expect 1\", length)\n}","handlingStrategy":"try-catch","validationCode":"// sanity-check the CONNECT_RESPONSE region before parsing\n// ensure at least tag+length+1 bytes remain for the enumerated field\nif len(buf) < pos+3 { return errors.New(\"CONNECT_RESPONSE truncated before enumerated field\") }","typeGuard":null,"tryCatchPattern":"v, err := ber.ReadEnumerated(r)\nif err != nil {\n    if strings.Contains(err.Error(), \"enumerate size is wrong\") {\n        // desync or nonstandard encoder: dump bytes and resynchronize\n    }\n    return err\n}","preventionTips":["Enable debug hex-dumps of CONNECT_RESPONSE for failing servers","Retry once on transient network errors before surfacing the error","Verify upstream field parsing consumes exact byte counts"],"tags":["rdp","ber","asn1","length-mismatch"],"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"}