CVE-2016-4289
A stack based buffer overflow vulnerability exists in the method receiving data from SysTreeView32 control of the GMER application. A specially created long path can lead to a buffer overflow on the stack resulting in code execution. An attacker needs to create path longer than 99 characters to trigger this vulnerability.
GMER 2.1.19357
http://www.gmer.net/
CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H/E:P/RC:C
CVSSv3 Calculator: https://www.first.org/cvss/calculator/3.0
Gmer can be used to detect and delete hidden files and folders. We can use this functionality by choosing the “Files” tab in the GMER application. Folders are presented there in the SysTreeView32 control. A directory name longer than 99 characters causes a stack based buffer overflow in the function resposible for receiving data from this control item. Let’s take a look at a vulnerable function and its surroundings.
sub_463880 proc near
var_DC= dword ptr -0DCh
this= dword ptr -0D8h
var_D4= dword ptr -0D4h
directoryName= word ptr -0D0h
var_8= dword ptr -8
hItem= dword ptr -4
arg_0= dword ptr 8
arg_4= dword ptr 0Ch
push ebp
mov ebp, esp
sub esp, 220
As we can see, the previous function prepares 220 bytes for local variables.
.text:0046393D push 200 ; cchTextMax
.text:00463942 lea edx, [ebp+pszText] ;directoryName
.text:00463948 push edx
.text:00463949 mov eax, [ebp+hItem]
.text:0046394C push eax
.text:0046394D mov ecx, [ebp+this]
.text:00463953 add ecx, 272
.text:00463959 call TreeView_GetItem_wrapper ; <------ OVERFLOW
Here we reach the call to the wrapper function of the TreeView_GetItem macro. We are looking at a buffer of size 200 expressed in characters (third parameter), everything looks correct and the buffer should be able to accommodate 200 ANSI chars. Stepping inside this call we see the code responsible for preparing the TVITEM structure:
.text:0040AAA0 TreeView_GetItem_wrapper proc near ; CODE XREF: sub_44CCC0+5C p
.text:0040AAA0 ; sub_44E150+5C p ...
.text:0040AAA0
.text:0040AAA0 var_30 = dword ptr -30h
.text:0040AAA0 tvITEM = dword ptr -2Ch
.text:0040AAA0 var_28 = dword ptr -28h
.text:0040AAA0 var_24 = dword ptr -24h
.text:0040AAA0 var_20 = dword ptr -20h
.text:0040AAA0 var_1C = dword ptr -1Ch
.text:0040AAA0 var_18 = dword ptr -18h
.text:0040AAA0 var_14 = dword ptr -14h
.text:0040AAA0 var_10 = dword ptr -10h
.text:0040AAA0 var_C = dword ptr -0Ch
.text:0040AAA0 var_8 = dword ptr -8
.text:0040AAA0 var_4 = dword ptr -4
.text:0040AAA0 hItem = dword ptr 8
.text:0040AAA0 pszText = dword ptr 0Ch
.text:0040AAA0 cchTextMax = dword ptr 10h
.text:0040AAA0
.text:0040AAA0 push ebp
.text:0040AAA1 mov ebp, esp
.text:0040AAA3 sub esp, 30h
.text:0040AAA6 mov [ebp+var_30], ecx
.text:0040AAA9 mov [ebp+tvITEM], 0
.text:0040AAB0 xor eax, eax
.text:0040AAB2 mov [ebp+var_28], eax
.text:0040AAB5 mov [ebp+var_24], eax
.text:0040AAB8 mov [ebp+var_20], eax
.text:0040AABB mov [ebp+var_1C], eax
.text:0040AABE mov [ebp+var_18], eax
.text:0040AAC1 mov [ebp+var_14], eax
.text:0040AAC4 mov [ebp+var_10], eax
.text:0040AAC7 mov [ebp+var_C], eax
.text:0040AACA mov [ebp+var_8], eax
.text:0040AACD mov [ebp+var_4], eax
.text:0040AAD0 mov [ebp+tvITEM], 1
.text:0040AAD7 mov ecx, [ebp+pszText]
.text:0040AADA mov [ebp+var_1C], ecx
.text:0040AADD mov edx, [ebp+cchTextMax]
.text:0040AAE0 mov [ebp+var_18], edx
.text:0040AAE3 mov eax, [ebp+hItem]
.text:0040AAE6 mov [ebp+var_28], eax
.text:0040AAE9 lea ecx, [ebp+tvITEM]
.text:0040AAEC push ecx
.text:0040AAED mov ecx, [ebp+var_30]
.text:0040AAF0 call sub_40AA80
.text:0040AAF5 mov esp, ebp
.text:0040AAF7 pop ebp
.text:0040AAF8 retn 0Ch
.text:0040AAF8 TreeView_GetItem_wrapper endp
Everything starts to be clear when we get into sub_40AA80:
.text:0040AA80 sub_40AA80 proc near ; CODE XREF: TreeView_GetItem_wrapper+50 p
.text:0040AA80
.text:0040AA80 this = dword ptr -4
.text:0040AA80 pTVITEM = dword ptr 8
.text:0040AA80
.text:0040AA80 push ebp
.text:0040AA81 mov ebp, esp
.text:0040AA83 push ecx
.text:0040AA84 mov [ebp+this], ecx
.text:0040AA87 mov eax, [ebp+pTVITEM]
.text:0040AA8A push eax
.text:0040AA8B push 0
.text:0040AA8D push 113Eh
.text:0040AA92 mov ecx, [ebp+this]
.text:0040AA95 call SendMessageA_to_SysTreeView32
.text:0040AA9A mov esp, ebp
.text:0040AA9C pop ebp
.text:0040AA9D retn 4
.text:0040AA9D sub_40AA80 endp
Another wrapper, this time on SendMessageA. We see here 3 parameters pushed on the stack for the SendMessageA api and the handle to SysTreeView32 is pushed inside the wrapper. Let’s jump over the wrapper code to the API call and see all the parameters pushed onto the stack:
00139430 004013B0 /CALL to SendMessageA from unpacked.004013AA
00139434 00010C02 |hWnd = 10C02
00139438 0000113E |Message = MSG(113E)
0013943C 00000000 |wParam = 0
00139440 00139470 \lParam = 139470
Structure
Address Name Type Value Hex Dump
00139470 _mask DWORD 00000001
00139474 hItem DWORD 001AE710
00139478 state DWORD 00000000
0013947C stateMask DWORD 00000000
00139480 pszText DWORD 001394BC
00139484 cchTextMax DWORD 000000C8
00139488 iImage DWORD 00000000
0013948C iSelectedImage DWORD 00000000
00139490 cChildren DWORD 00000000
00139494 lParam DWORD 00000000
Now the most interesting parameter for our purposes is a Message and its value 113E. Resolving this hexadecimal value to a more understandable form we get TVM_GETITEMW. While the author used the SendMessage version for ANSI, the number of signs passed to TVITEM cchTextMax value means now that our buffer is able to accommodate 200 UNICODE characters. This incorrect size value allows an attacker to overflow the buffer and gain code execution.
python:
import os
os.mkdir("C:\\" + "A"*100);
The buffer that accommodates data from a SysTreeView32 control should be declared as wchar_t buffer to accommodate Unicode characters. Additionally, its size should be increased to 256 * sizeof(wchar_t) to be able to receive the entire directory name.
2016-06-01 - Discovery
2016-06-10 - Reported
2016-11-03 - Released
Discovered by Marcin Icewall Noga of Cisco Talos.