In March 2019, our automatic Exploit Prevention (EP) systems detected an attempt to exploit a vulnerability in the Microsoft Windows operating system. Further analysis of this event led to us discovering a zero-day vulnerability in win32k.sys. It was the fifth consecutive exploited Local Privilege Escalation vulnerability in Windows that we have discovered in recent months using our technologies. The previous ones were:
- Zero-day exploit (CVE-2018-8453) used in targeted attacks
- A new exploit for zero-day vulnerability CVE-2018-8589
- Zero-day in Windows Kernel Transaction Manager (CVE-2018-8611)
- The fourth horseman: CVE-2019-0797 vulnerability
On March 17, 2019 we reported our discovery to Microsoft; the company confirmed the vulnerability and assigned it CVE-2019-0859. Microsoft have just released a patch, part of its update, crediting Kaspersky Lab researchers Vasiliy Berdnikov and Boris Larin.
Technical details
CVE-2019-0859 is a Use-After-Free vulnerability that is presented in the CreateWindowEx function. During execution CreateWindowEx sends the message WM_NCCREATE to the window when it’s first created. By using the SetWindowsHookEx function, it is possible to set a custom callback that can handle the WM_NCCREATE message right before calling the window procedure.
In win32k.sys all windows are presented by the tagWND structure which has an “fnid” field also known as Function ID. The field is used to define the class of a window; all windows are divided into classes such as ScrollBar, Menu, Desktop and many others. We have already written about Function ID related bugs.
During the WM_NCCREATE callback, the Function ID of a window is set to 0 and this allowed us to set extra data for the window from inside our hook. More importantly, we were able to change the address for the window procedure that was executed immediately after our hook. The change of window procedure to the menu window procedure leads to the execution of xxxMenuWindowProc and the function initiates Function ID to FNID_MENU because the current message is equal to WM_NCCREATE. But the most important part is that the ability to manipulate extra data prior to setting Function ID to FNID_MENU can force the xxxMenuWindowProc function to stop initialization of the menu and return FALSE. Because of that, sending of the NCCREATE message will be considered a failed operation and CreateWindowEx function will stop execution with a call to FreeWindow. Because our MENU-class window was not actually initialized, it allows us to gain control over the address of the memory block that is freed.
The exploit we found in the wild was targeting 64-bit versions of Windows (from Windows 7 to older builds of Windows 10) and exploited the vulnerability using the well-known HMValidateHandle technique to bypass ASLR.
After a successful exploitation, the exploit executed PowerShell with a Base64 encoded command. The main aim of this command was to download a second-stage script from https//pastebin.com. The second stage PowerShell executes the final third stage, which is also a PowerShell script.
The third script is very simple and does the following:
- Unpacks shellcode
- Allocates executable memory
- Copies shellcode to allocated memory
- Calls CreateThread to execute shellcode
The main goal of the shellcode is to make a trivial HTTP reverse shell. This helps the attacker gain full control over the victim’s system.
Kaspersky Lab products detected this exploit proactively through the following technologies:
- Behavioral detection engine and Exploit Prevention for endpoint products;
- Advanced Sandboxing and Anti-Malware engine of the Kaspersky Anti Targeted Attack (KATA) platform.
Kaspersky Lab verdicts for the artifacts used in this and related attacks are:
- HEUR:Exploit.Win32.Generic
- HEUR:Trojan.Win32.Generic
- PDM:Exploit.Win32.Generic