Information

File: protocols\rdp\plugins\guac-common-svc\guac-common-svc.c
Function: guac_rdp_common_svc_handle_open_event()

  1. RDP channel messages support a simple fragmentation that is determined by the “flags” field in the message.
  2. There are improper state machine checks in FreeRDP and in the Guacamole Proxy.
  3. A malicious RDP server could send channel fragments without sending the “first” fragment in the chain.
  4. This will lead to the use of a dangling pointer that remained from the previous channel message, and ultimately enables a malicious RDP server to take over the Guacamole Proxy.

Code Snippet:

/* If receiving first chunk, allocate sufficient space for all remaining chunks */
if (data_flags & CHANNEL_FLAG_FIRST) {

	/* Limit maximum received size */
	if (total_length > GUAC_SVC_MAX_ASSEMBLED_LENGTH) {
		
		total_length = GUAC_SVC_MAX_ASSEMBLED_LENGTH;
	}

	svc->_input_stream = Stream_New(NULL, total_length);
}

// EI-DBG: Missing input check that svc->_input_stream != NULL.
// EI-DBG: This leads to the use of a dangling "stream" instead.

/* Add chunk to buffer only if sufficient space remains */
if (Stream_EnsureRemainingCapacity(svc->_input_stream, data_length))
	Stream_Write(svc->_input_stream, data, data_length);
else
	

/* Fire event once last chunk has been received */
if (data_flags & CHANNEL_FLAG_LAST) {

	Stream_SealLength(svc->_input_stream);
	Stream_SetPosition(svc->_input_stream, 0);

	/* Handle channel-specific data receipt tasks, if any */
	if (svc->_receive_handler)
		svc->_receive_handler(svc, svc->_input_stream);

	// EI-DBG: The stream is being free()ed here, *without* setting svc->_input_stream to NULL.
	Stream_Free(svc->_input_stream, TRUE);
}

Attachments:
CVE-2020-9498.py
private_no_pass.key
selfsigned.crt

References:
https://research.checkpoint.com/2020/apache-guacamole-rce/
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9498
https://github.com/apache/guacamole-server/commit/a0e11dc81727528224d28466903454e1cb0266bb