shadow1ng/fscan · error

unsupported Capability type 0x%04x

Error message

unsupported Capability type 0x%04x

What it means

readCapability in libs/grdp/protocol/pdu/caps.go parses one TS_CAPABILITYSET entry from a Demand-Active or Confirm-Active PDU. When the 16-bit capabilitySetType is not one of the CAPSETTYPE_* values the library has a struct for, it returns this error instead of guessing at the binary layout. It indicates the remote RDP server advertised a capability set this client does not implement.

Source

Thrown at libs/grdp/protocol/pdu/caps.go:750

		c = &DrawGDIPlusCapability{}
	case CAPSETTYPE_BITMAP_CODECS:
		c = &BitmapCodecsCapability{}
	case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
		c = &BitmapCacheHostSupportCapability{}
	case CAPSETTYPE_LARGE_POINTER:
		c = &LargePointerCapability{}
	case CAPSTYPE_RAIL:
		c = &RemoteProgramsCapability{}
	case CAPSTYPE_WINDOW:
		c = &WindowListCapability{}
	case CAPSETTYPE_COMPDESK:
		c = &DesktopCompositionCapability{}
	case CAPSETTYPE_SURFACE_COMMANDS:
		c = &SurfaceCommandsCapability{}
	case CAPSSETTYPE_FRAME_ACKNOWLEDGE:
		c = &FrameAcknowledgeCapability{}
	default:
		err := errors.New(fmt.Sprintf("unsupported Capability type 0x%04x", capType))
		glog.Error(err)
		return nil, err
	}
	if err := struc.Unpack(capReader, c); err != nil {
		glog.Error("Capability unpack error", err, fmt.Sprintf("0x%04x", capType), hex.EncodeToString(capBytes))
		return nil, err
	}
	glog.Debugf("Capability<%s>: %+v", c.Type(), c)
	return c, nil
}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Capture the printed 0x%04x value and add a matching CAPSETTYPE_* case + struct in caps.go readCapability, or make the default case skip the capability using its length field instead of failing
  2. Connect with client capability negotiation restricted to well-supported caps, or update/pin a grdp version supporting the server's cap sets
  3. Verify the stream is not desynchronized (a wrong capLen earlier in the list makes a later length field read as capType); test against a known-good server to confirm
  4. If you control the fork, log the raw cap bytes (already hex-encoded in the nearby unpack error path) and compare with MS-RDPBCGR to identify the set

Example fix

// before (caps.go readCapability)
default:
	err := errors.New(fmt.Sprintf("unsupported Capability type 0x%04x", capType))
	glog.Error(err)
	return nil, err
// after: skip unknown sets using the already-read length
default:
	if _, err := io.ReadFull(r, make([]byte, int(capLen)-4)); err != nil {
		return nil, err
	}
	return readCapability(r) // next capability in the list
Defensive patterns

Strategy: try-catch

Try / catch

err := client.Connect(addr, opts)
if err != nil {
    if strings.Contains(err.Error(), "unsupported Capability type") {
        // fall back to a server profile with restricted caps or report unsupported server
        return fmt.Errorf("server advertises unsupported RDP capability: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling grdp's RDP connect/session flow against a server whose Demand-Active (readDemandActivePDU) or Confirm-Active (readConfirmActivePDU) PDU contains a capability set type outside the supported switch (e.g. CAPSETTYPE_MULTIFRAGMENTUPDATE, share, or window-activation caps).

Common situations: Connecting to newer Windows servers or hypervisor consoles (Hyper-V/VMWare consoles) that advertise extended capability sets; mismatched security/negotiation settings causing misparse of the capability stream; forked/older grdp not updated for newer MS-RDPBCGR cap types.

Related errors


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