Information

File: libfreerdp\core\update.c
Function: update_read_bitmap_update()

The variable “bitmapUpdate->number” is read from the input stream “s” and can be in the range: 0 - 0xFFFF.
In the case that it is bigger than “bitmapUpdate->count” there will be an attempt to calculate the appropriate new capacity for the buffer:
“count = bitmapUpdate->number * 2;”
However, since “count” is of type “UINT16”, it can truncate the calculated value, making “realloc()” allocate a buffer that will be too small:
1) “bitmapUpdate->count” = 0x8000
2) “bitmapUpdate->count” * 2 = 0x10000
3) “count” = 0x10000 & 0xFFFF = 0
Later on, the “for” loop will use the high value of “bitmapUpdate->number” and will write outside of the small allocated heap buffer.

Code Snippet:

Stream_Read_UINT16(s, bitmapUpdate->number); /* numberRectangles (2 bytes) */
WLog_Print(update->log, WLOG_TRACE, "BitmapUpdate: %"PRIu32"", bitmapUpdate->number);

if (bitmapUpdate->number > bitmapUpdate->count)
{
	UINT16 count;
	BITMAP_DATA* newdata;
	count = bitmapUpdate->number * 2;
	newdata = (BITMAP_DATA*) realloc(bitmapUpdate->rectangles,
		                                 sizeof(BITMAP_DATA) * count);

	if (!newdata)
		goto fail;

	bitmapUpdate->rectangles = newdata;
	ZeroMemory(&bitmapUpdate->rectangles[bitmapUpdate->count],
	           sizeof(BITMAP_DATA) * (count - bitmapUpdate->count));
	bitmapUpdate->count = count;
}

/* rectangles */
for (i = 0; i < bitmapUpdate->number; i++)
{
	if (!update_read_bitmap_data(update, s, &bitmapUpdate->rectangles[i]))
		goto fail;
}

ASAN Output:

[15:09:55:016] [16394:16395] [INFO][com.freerdp.client.common.cmdline] - loading channelEx cliprdr
[15:09:55:202] [16394:16395] [INFO][com.freerdp.gdi] - Local framebuffer format  PIXEL_FORMAT_BGRX32
[15:09:55:202] [16394:16395] [INFO][com.freerdp.gdi] - Remote framebuffer format PIXEL_FORMAT_RGB16
[15:09:55:229] [16394:16395] [INFO][com.winpr.clipboard] - initialized POSIX local file subsystem
=================================================================
==16394==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d000006018 at pc 0x7fbf40cf55e7 bp 0x7fbf334f92e0 sp 0x7fbf334f92d0
READ of size 8 at 0x60d000006018 thread T1
    #0 0x7fbf40cf55e6 in free_bitmap_update (/usr/local/lib/libfreerdp2.so.2+0xc95e6)
    #1 0x7fbf40ddaf9f in update_read_bitmap_update (/usr/local/lib/libfreerdp2.so.2+0x1aef9f)
    #2 0x7fbf40dc2941 in fastpath_recv_update (/usr/local/lib/libfreerdp2.so.2+0x196941)
    #3 0x7fbf40dc3a9a in fastpath_recv_updates (/usr/local/lib/libfreerdp2.so.2+0x197a9a)
    #4 0x7fbf40db7545 in rdp_recv_pdu (/usr/local/lib/libfreerdp2.so.2+0x18b545)
    #5 0x7fbf40db907a in rdp_recv_callback (/usr/local/lib/libfreerdp2.so.2+0x18d07a)
    #6 0x7fbf40dcda50 in transport_check_fds (/usr/local/lib/libfreerdp2.so.2+0x1a1a50)
    #7 0x7fbf40db9ecf in rdp_check_fds (/usr/local/lib/libfreerdp2.so.2+0x18decf)
    #8 0x7fbf40d81eba in freerdp_check_fds (/usr/local/lib/libfreerdp2.so.2+0x155eba)
    #9 0x7fbf40d84107 in freerdp_check_event_handles (/usr/local/lib/libfreerdp2.so.2+0x158107)
    #10 0x449e36 in xf_client_thread (/home/XXX/FreeRDP-2.0.0-rc3/xfreerdp+0x449e36)
    #11 0x7fbf403f0ec5 in thread_launcher (/usr/local/lib/libwinpr2.so.2+0x122ec5)
    #12 0x7fbf3fcee6b9 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x76b9)
    #13 0x7fbf4000b41c in clone (/lib/x86_64-linux-gnu/libc.so.6+0x10741c)

0x60d000006018 is located 8 bytes to the left of 136-byte region [0x60d000006020,0x60d0000060a8)
allocated by thread T1 here:
    #0 0x7fbf4297e79a in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9879a)
    #1 0x7fbf425d3220 in XCreateImage (/usr/lib/x86_64-linux-gnu/libX11.so.6+0x27220)

Thread T1 created by T0 here:
    #0 0x7fbf4291c253 in pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x36253)
    #1 0x7fbf403f0bf4 in winpr_StartThread (/usr/local/lib/libwinpr2.so.2+0x122bf4)
    #2 0x7fbf403f14b7 in CreateThread (/usr/local/lib/libwinpr2.so.2+0x1234b7)
    #3 0x446f7f in xfreerdp_client_start (/home/XXX/FreeRDP-2.0.0-rc3/xfreerdp+0x446f7f)
    #4 0x4079d0 in main (/home/XXX/FreeRDP-2.0.0-rc3/xfreerdp+0x4079d0)
    #5 0x7fbf3ff2482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 free_bitmap_update
Shadow bytes around the buggy address:
  0x0c1a7fff8bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8be0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00 00
  0x0c1a7fff8bf0: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa
=>0x0c1a7fff8c00: fa fa fa[fa]00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff8c10: 00 00 00 00 00 fa fa fa fa fa fa fa fa fa 00 00
  0x0c1a7fff8c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
  0x0c1a7fff8c30: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c1a7fff8c40: 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa
  0x0c1a7fff8c50: fa fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==16394==ABORTING

Attachments:
CVE-2018-8786_PoC.py
private_no_pass.key
selfsigned.crt

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