“Double Kill” is an Internet Explorer(IE) Zero-Day exploit which was discovered in the wild and fixed in the Microsoft May Patch. It exploits a use-after-free vulnerability of vbscript.dll to execute arbitrary code when a vulnerable system browses a malicious web page via IE. Multiple exploit kits have already added this exploit, and it is still active in the wild.
This use-after-free bug causes a type confusion in vbscript.dll, which allows the attacker to access and overwrite the whole user space memory address. However, before the shellcode can be finally executed, the attacker has to get the address of multiple system DLL addresses to locate the addresses of the functions “ntdll!NtContinue” and “ntdll!VirtualProtect”, which are popularly used to bypass the Windows system data execution prevention(DEP) and render heap code execution. In this post, the team at FortiGuard Labs looks deeply into the VBScript codes to expose the DLL address leaking trick used by this exploit.
The following public published exploit is used in our analysis (Comments added by me have been highlighted).
Part of the Exploit:
Firstly, the exploit uses “UAF” and “InitObjects” functions to overwrite the type fields of two BSTR objects so that these two objects can be used to write and read arbitrary user space memory address.
“LLLL” and “IIIIL” are both objects of the following VBScript Class LLIIL(class 1) which includes three members: mem, P and SetProp.
The following diagram shows how to access the data of a member of a VBScript Class. Vbscript.dll uses the VARINT structure to indicate the type and value of the class member. It stores the VARINT structure in the VVAL structure.
VARINT is defined as following:
The function CScriptRuntime::GetVarAdr is used to retrieve the address of the VBScript Class object. It searches the NameList to find the address of VVAL (which is also the address of VARINT) and stores it in a VT_DISPATCH (VARINT VAR type 0x09).
Let’s check the CScriptRuntime variable(0x5ac1f0) in the memory:
InitObjects is called after UAF to do the type confusion, it invokes the SetProp class function to change the type field of the class member “mem”.
Let’s check the memory of “LLLL.mem” after type confusion:
By using this one-dimensional array, the exploit can access the memory address from 0 to 0x7fffffff (the highest user space address.) Any write operation for “LLLL.mem(i)” copies the value to the memory address i. The exploit creates the type confusion again and overwrites the type field of “IIIIL.mem”. Let’s have a look at “IIIIL.mem” in memory after the type confusion:
After overwriting the type field of “IIIIL.mem”, any read operation for “IIIIL.mem(i)” returns the memory data at address (i+8).
Secondly, the exploit uses function “LeakVBAddr” to fetch the address of CScriptEntryPoint object.
Let’s have a look the memory changes when executing “LLLL.mem(ILII+8)=ILIIIL” step by step.
Function GetMemValue is called later to read the memory at LLLL.mem(ILII+8):
Let’s check the memory after “LLLL.mem(ILII)=3”:
Since the type of LLLL.mem(ILII+8) changes to VT_I32, which means it is just a 32bit integer value. We can easily get this 32bit integer by executing “GetMemValue=LLLL.mem(ILII+8)”. Finally, the exploit gets the return value of 0x5ac658 from the function LeakVBAddr.
Finally, the exploit uses function GetUint32 to read the memory data at address 0x5ac658 to get the VirtualTable address. GetBaseByDOSmodeSearch is called later to search the DLL file header based on the VirtualTable address to get the base address of vbscript.dll.
Fortinet released IPS signature MS.Windows.VBScript.Engine.Class_Terminate.Code.Execution to address this vulnerability.