CVE-2018-8785 (C, published 2018-11-29T18:29Z)
Description: value: FreeRDP prior to version 2.0.0-rc4 contains a Heap-Based Buffer Overflow in function zgfx_decompress() that results in a memory corruption and probably even a remote code execution.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-787 \u2014 Out-of-bounds Write
The product writes data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/FreeRDP/FreeRDP
Files changed:
include/freerdp/codec/zgfx.h
libfreerdp/codec/zgfx.c
Commit message: Fixed CVE-2018-8785

Thanks to Eyal Itkin from Check Point Software Technologies.


Vulnerable code:
struct _ZGFX_CONTEXT
{
	BOOL Compressor;

	const BYTE* pbInputCurrent;
	const BYTE* pbInputEnd;

	UINT32 bits;
	UINT32 cBitsRemaining;
	UINT32 BitsCurrent;
	UINT32 cBitsCurrent;

	BYTE OutputBuffer[65536];
	UINT32 OutputCount;

	BYTE HistoryBuffer[2500000];
	UINT32 HistoryIndex;
	UINT32 HistoryBufferSize;
};
FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags);
 
	int prefixLength;
	int prefixCode;
	int valueBits;
	int tokenType;
#define zgfx_GetBits(_zgfx, _nbits) \
	while (_zgfx->cBitsCurrent < _nbits) { \
		_zgfx->BitsCurrent <<= 8; \
		if (_zgfx->pbInputCurrent < _zgfx->pbInputEnd) \
			_zgfx->BitsCurrent += *(_zgfx->pbInputCurrent)++; \
		_zgfx->cBitsCurrent += 8; \
	} \
	_zgfx->cBitsRemaining -= _nbits; \
	_zgfx->cBitsCurrent -= _nbits; \
	_zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent; \
	int extra;


Fixed code:
FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize,
                                BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize,
                              BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst,
                                        const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags);

	UINT32 prefixLength;
	UINT32 prefixCode;
	UINT32 valueBits;
	UINT32 tokenType;
struct _ZGFX_CONTEXT
{
	BOOL Compressor;

	const BYTE* pbInputCurrent;
	const BYTE* pbInputEnd;

	UINT32 bits;
	UINT32 cBitsRemaining;
	UINT32 BitsCurrent;
	UINT32 cBitsCurrent;

	BYTE OutputBuffer[65536];
	UINT32 OutputCount;

	BYTE HistoryBuffer[2500000];
	UINT32 HistoryIndex;
	UINT32 HistoryBufferSize;
};

static INLINE BOOL zgfx_GetBits(ZGFX_CONTEXT* _zgfx, UINT32 _nbits)
{
	if (!_zgfx)
		return FALSE;

	while (_zgfx->cBitsCurrent < _nbits)
	{
		_zgfx->BitsCurrent <<= 8;

		if (_zgfx->pbInputCurrent < _zgfx->pbInputEnd)
			_zgfx->BitsCurrent += *(_zgfx->pbInputCurrent)++;

		_zgfx->cBitsCurrent += 8;
	}

	_zgfx->cBitsRemaining -= _nbits;
	_zgfx->cBitsCurrent -= _nbits;
	_zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent;
}
	UINT32 extra = 0;


		size_t used = 0;
			if (zgfx->OutputCount > UINT32_MAX - used)
				goto fail;

			if (used + zgfx->OutputCount > uncompressedSize)
				goto fail;

			used += zgfx->OutputCount;