CVE-2018-8786
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