shadow1ng/fscan · error

invalid RDP random length: client=%d server=%d

Error message

invalid RDP random length: client=%d server=%d

What it means

generateKeys derives the RDP session encryption keys from the client and server randoms, which must each be at least 32 bytes. If either random is shorter (garbled or truncated server/client random data from the GCC conference create response), the library refuses to derive keys with this error.

Source

Thrown at libs/grdp/protocol/sec/sec.go:619

@summary: Generate master secret
@param secret: secret
@param clientRandom : client random
@param serverRandom : server random
*/
func sessionKeyBlob(secret, random1, random2 []byte) []byte {
	sh1 := saltedHash([]byte("X"), secret, random1, random2)
	sh2 := saltedHash([]byte("YY"), secret, random1, random2)
	sh3 := saltedHash([]byte("ZZZ"), secret, random1, random2)
	ms := bytes.NewBuffer(nil)
	ms.Write(sh1)
	ms.Write(sh2)
	ms.Write(sh3)
	return ms.Bytes()

}
func generateKeys(clientRandom, serverRandom []byte, method uint32) ([]byte, []byte, []byte, error) {
	if len(clientRandom) < 32 || len(serverRandom) < 32 {
		return nil, nil, nil, fmt.Errorf("invalid RDP random length: client=%d server=%d", len(clientRandom), len(serverRandom))
	}

	b := &bytes.Buffer{}
	b.Write(clientRandom[:24])
	b.Write(serverRandom[:24])
	preMasterHash := b.Bytes()
	glog.Debug("preMasterHash:", hex.EncodeToString(preMasterHash))

	masterHash := masterSecret(preMasterHash, clientRandom, serverRandom)
	glog.Debug("masterHash:", hex.EncodeToString(masterHash))

	sessionKey := sessionKeyBlob(masterHash, clientRandom, serverRandom)
	glog.Debug("sessionKey:", hex.EncodeToString(sessionKey))

	macKey128 := sessionKey[:16]
	initialFirstKey128 := finalHash(sessionKey[16:32], clientRandom, serverRandom)
	initialSecondKey128 := finalHash(sessionKey[32:48], clientRandom, serverRandom)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Dump the clientRandom/serverRandom lengths at the call site to see which side is short.
  2. Verify the GCC Conference Create Response parser handles all server variants (per MS-RDPBCGR 2.2.1.4).
  3. Update the grdp library — fixes for nonstandard server randoms may exist upstream.
  4. If the server truly sends short randoms, the connection cannot use standard RDP encryption; require NLA/TLS mode instead.
Defensive patterns

Strategy: validation

Validate before calling

func randomsValid(clientRandom, serverRandom []byte) bool {
	return len(clientRandom) >= 32 && len(serverRandom) >= 32
}
if !randomsValid(cr, sr) { return errors.New("short RDP randoms; refusing key derivation") }

Type guard

func hasFullRandoms(cr, sr []byte) bool { return len(cr) >= 32 && len(sr) >= 32 }

Try / catch

m1, m2, k, err := generateKeys(clientRandom, serverRandom, method)
if err != nil && strings.HasPrefix(err.Error(), "invalid RDP random length") {
	return fmt.Errorf("server sent malformed/random data; aborting standard-security handshake: %w", err)
}

Prevention

When it happens

Trigger: The parsed ClientRandom/ServerRandom arrays from the GCC data are shorter than 32 bytes — usually caused by malformed or incorrectly parsed server GCC response, or by a nonstandard RDP server sending abbreviated randoms.

Common situations: Connecting to non-Windows or embedded RDP servers (thin clients, appliances) with protocol quirks; corrupted TLS-decrypted handshake data; a parser bug mis-slicing the GCC fields.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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