foreword
As mentioned above, CVE-2019-1208
it is UAF
a vulnerability, this type of security hole can destroy valid data, cause process crash, and can be carefully exploited to eventually lead to arbitrary code execution. For CVE-2019-1208 introduced in this article, an attacker who successfully exploits this vulnerability can obtain the current user privileges of the system. If the current user has admin privileges, an attacker can hijack the system—from installing or uninstalling programs, viewing and modifying data, to creating users with full privileges.
potential impact
There is also a more tangible attack scenario where an attacker sends phishing emails to unsuspecting users and tricks them into visiting a malicious website through IE (CVE-2019-1208 exists).
Alternatively, an attacker could send a spam email with an attachment containing an exploit for the vulnerability. These attachments can be Microsoft Office documents with the IE rendering engine enabled, or applications that embed ActiveX controls that contain exploits.
Attackers can also place attack code on some legitimate websites, such as those that accept user input.
The following figure VbsJoin
shows the code flow:
How was the vulnerability discovered?
My research started BinDiff
when I was trying to compare vbscript.dll
the May and June versions, looking for functions that were changed, and this module contains API functions for the VBScript engine. Eventually I found some fixes via SafeArrayAddRef , SafeArrayReleaseData and SafeArrayReleaseDescriptor functions
However, inspired by the vulnerability CVE-2018-8373 I found before , after further analysis, I used VBScriptClass to trigger the UAF vulnerability through the following steps:
-
arr = Array(New MyClass)
, create a SafeArray and save it at arr[0]VBScriptclass: MyClass
-
Callback: arr = Array(0)
,Join(arr)
will trigger the callback function of MyClassPublic Default Property Get
. In this callback, a new SafeArray is created for the variable, as shown in the figure below and this new SafeArray is notSafeArrayAddRef
protected by the function. Therefore, the normal code flow assumption is broken by this callback
-
arr(0) = Join(arr)
, whenPublic Default Property Get
returning from, the code in VBsJoin will callSafeArrayReleaseData
andSafeArrayReleaseDescriptor
to decrement the reference count ofSafeArrayData
andSafeArrayDescriptor
. However, the new SafeArray is notSafeArrayAddRef
protected, andSafeArrayData
hasSafeArrayDescriptor
a reference count of 0.SafeArrayData
Therefore, the sum of the new SafeArray will be freedSafeArrayDescriptor
in the function sumSafeArrayReleaseData
, as shown in the following figure:SafeArrayReleaseDescriptor
where the code snapshot shows in-memory
arr = Array(New MyClass)
(top), in-memoryarr = Array(0)
andcallback
at the bottom
When saving the return value of VbsJoin to arr(0), PoC vbscript!AccessArray
crashes in (see the figure below), because SafeArrayDescriptor
it is free, Variant arr still saves the released SafeArrayDescriptor
pointer.
Code snapshot showing how the PoC
vbscript!AccessArray
triggers the crash in
Did the PoC successfully trigger UAF?
In a way, the answer is yes
To demonstrate how to fully trigger UAF, I used basic string/binary string(BSTR)
as data structure. SafeArray is a multidimensional array, but since VBsJoin can only handle one-bit arrays, I changed the dimensions of the SafeArray in the callback.
Unfortunately, it still doesn't work, it throws a runtime error stating that the array type doesn't match in the Join. But it doesn't matter, I use On Error Resume Next to bypass this runtime error, the following picture shows the modified PoC:
After getting 0x20 bytes of freed memory, I use a BSTR of size 0x20 bytes to fake a larger size SafeArray.
By using heap feng shui , this BSTR can stably reuse 0x20 bytes of freed memory, as shown in the following figure:
I finally got a fake one-dimensional array SafeArray, with a total of 0x7fffffff elements, each element size is 1 byte, as shown below:
Fake SafeArray (top) and fixed address for read/write (bottom)
So far I've been able to fake a SafeArray that can be used to read/write memory from 0x00000000 to 0x7fffffff
In order to leak some read/write addresses for exploitation, I refer to Simon Zuckerbraun's previous research and use heap spraying to get some fixed read/write addresses (0x28281000)
From UAF to RCE
As described in Simon Zuckerbraun's blog, I used the Scripting.Dictionary object to accomplish remote code execution, but used another method to fake a fake Dictionary. This time, I used a BSTR and brought them out
The memory layout of Faked Dictionary is as follows:
- Use the memory read/write functions to read the original Dictionary memory, save its data to a BSTR, and replace it
VBADictionary::Exists
withkernel32!Winexec
Winexec
Write the parameters used later\..\clac.exe
into this BSTR- Save this BSTR to
util_memory+0x1000
, and modifyutil_memory + 0x1000 – 8 = 9
tofake_array(util_memory + 0x1000)
make an object - Use
fake_array(util_memory + &h1000)
, usedummy
to triggerWinexec
the function
Finally, using the result, the calculator pops up successfully:
What does this vulnerability mean for IE?
On August 13, 2019, VBScript, which was disabled in Windows 10, was also disabled in Windows 7 and 8 for IE. Therefore, the PoC detailed above was developed in local mode. But as Microsoft says, this setting can still be enabled through the registry or group policy. Likewise, users and organizations should always adopt best practices: keeping systems patched and updated, disabling components that are not needed (or limiting use), and promoting cybersecurity awareness, such as spam and other social engineering threats
Full details of the study are in this technical brief