CVE-2018-8789: Out-of-bounds Read (CWE-125)
value: FreeRDP prior to version 2.0.0-rc4 contains several Out-Of-Bounds Reads in the NTLM Authentication module that results in a Denial of Service (segfault).
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.5
Published: 2018-11-29T18:29Z
Repository: https://github.com/FreeRDP/FreeRDP
Language: C
Files changed: winpr/libwinpr/sspi/NTLM/ntlm_message.c
Commit date: 2018-11-20 11:08:31 +0100
Commit message: Fixed CVE-2018-8789

Thanks to Eyal Itkin from Check Point Software Technologies.

Diff: diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c
index d78560497..ab42dc737 100644
--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c
+++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c
@@ -72,11 +72,11 @@ static const char* const NTLM_NEGOTIATE_STRINGS[] =
 	"NTLMSSP_REQUEST_TARGET",
 	"NTLMSSP_NEGOTIATE_OEM",
 	"NTLMSSP_NEGOTIATE_UNICODE"
 };
 
-void ntlm_print_negotiate_flags(UINT32 flags)
+static void ntlm_print_negotiate_flags(UINT32 flags)
 {
 	int i;
 	const char* str;
 	WLog_INFO(TAG, "negotiateFlags \"0x%08"PRIX32"\"", flags);
 
@@ -88,11 +88,11 @@ void ntlm_print_negotiate_flags(UINT32 flags)
 			WLog_INFO(TAG, "\t%s (%d),", str, (31 - i));
 		}
 	}
 }
 
-int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
+static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
 {
 	if (Stream_GetRemainingLength(s) < 12)
 		return -1;
 
 	Stream_Read(s, header->Signature, 8);
@@ -102,48 +102,50 @@ int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
 		return -1;
 
 	return 1;
 }
 
-void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
+static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
 {
 	Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE));
 	Stream_Write_UINT32(s, header->MessageType);
 }
 
-void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
+static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
 {
 	CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
 	header->MessageType = MessageType;
 }
 
-int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
+static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
 {
 	if (Stream_GetRemainingLength(s) < 8)
 		return -1;
 
 	Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */
 	Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */
 	Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
 	return 1;
 }
 
-void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
+static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
 {
 	if (fields->MaxLen < 1)
 		fields->MaxLen = fields->Len;
 
 	Stream_Write_UINT16(s, fields->Len); /* Len (2 bytes) */
 	Stream_Write_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */
 	Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
 }
 
-int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
+static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
 {
 	if (fields->Len > 0)
 	{
-		if ((fields->BufferOffset + fields->Len) > Stream_Length(s))
+		const UINT64 offset = (UINT64)fields->BufferOffset + (UINT64)fields->Len;
+
+		if (offset > Stream_Length(s))
 			return -1;
 
 		fields->Buffer = (PBYTE) malloc(fields->Len);
 
 		if (!fields->Buffer)
@@ -154,20 +156,20 @@ int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
 	}
 
 	return 1;
 }
 
-void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
+static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
 {
 	if (fields->Len > 0)
 	{
 		Stream_SetPosition(s, fields->BufferOffset);
 		Stream_Write(s, fields->Buffer, fields->Len);
 	}
 }
 
-void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
+static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
 {
 	if (fields)
 	{
 		if (fields->Buffer)
 		{
@@ -178,11 +180,11 @@ void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
 			fields->BufferOffset = 0;
 		}
 	}
 }
 
-void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name)
+static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name)
 {
 	WLog_DBG(TAG, "%s (Len: %"PRIu16" MaxLen: %"PRIu16" BufferOffset: %"PRIu32")",
 	         name, fields->Len, fields->MaxLen, fields->BufferOffset);
 
 	if (fields->Len > 0)

Vulnerable code: void ntlm_print_negotiate_flags(UINT32 flags)
int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
		if ((fields->BufferOffset + fields->Len) > Stream_Length(s))
void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name)
Fixed code: static void ntlm_print_negotiate_flags(UINT32 flags)
static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
		const UINT64 offset = (UINT64)fields->BufferOffset + (UINT64)fields->Len;

		if (offset > Stream_Length(s))
static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name)