Information

File: libfreerdp\codecs\zgfx.c
Function: zgfx_decompress()

The fragmentation implementation uses two different length fields, without proper checks that they match each other.
1) Variable “uncompressedSize” represents the total length, and used for allocating the dest buffer named “pConcatenated”
2) Variables “segmentCount” and “segmentSize” are used for reading the fragments (and decompressing them)
3) Using “uncompressedSize” = 100, and 1 segment of “2000” we could make “CopyMemory()” overflow the allocated heap buffer with attacker controlled content.

Code Snippet:

Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */
Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */

if (Stream_GetRemainingLength(stream) < segmentCount * sizeof(UINT32))
	goto fail;

pConcatenated = (BYTE*) malloc(uncompressedSize);

if (!pConcatenated)
	goto fail;

*ppDstData = pConcatenated;
*pDstSize = uncompressedSize;

for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
{
	if (Stream_GetRemainingLength(stream) < sizeof(UINT32))
		goto fail;

	Stream_Read_UINT32(stream, segmentSize); /* segmentSize (4 bytes) */

	if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
		goto fail;

	CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount);
	pConcatenated += zgfx->OutputCount;
}


References:
https://research.checkpoint.com/reverse-rdp-attack-code-execution-on-rdp-clients
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-8785