The IBM X-Force Research team has identified a significant data manipulation vulnerability (CVE-2014-6332) with a CVSS score of 9.3 in every version of Microsoft Windows from Windows 95 onward.
We reported this issue with a working proof-of-concept exploit back in May 2014, and today, Microsoft is patching it. It can be exploited remotely since Microsoft Internet Explorer (IE) 3.0. This complex vulnerability is a rare, “unicorn-like” bug found in code that IE relies on but doesn’t necessarily belong to. The bug can be used by an attacker for drive-by attacks to reliably run code remotely and take over the user’s machine — even sidestepping the Enhanced Protected Mode (EPM) sandbox in IE 11 as well as the highly regarded Enhanced Mitigation Experience Toolkit (EMET) anti-exploitation tool Microsoft offers for free.
What Does This Mean?
First, this means that significant vulnerabilities can go undetected for some time. In this case, the buggy code is at least 19 years old and has been remotely exploitable for the past 18 years. Looking at the original release code of Windows 95, the problem is present. With the release of IE 3.0, remote exploitation became possible because it introduced Visual Basic Script (VBScript). Other applications over the years may have used the buggy code, though the inclusion of VBScript in IE 3.0 makes it the most likely candidate for an attacker. In some respects, this vulnerability has been sitting in plain sight for a long time despite many other bugs being discovered and patched in the same Windows library (OleAut32).
Second, it indicates that there may be other bugs still to be discovered that relate more to arbitrary data manipulation than more conventional vulnerabilities such as buffer overflows and use-after-free issues. These data manipulation vulnerabilities could lead to substantial exploitation scenarios from the manipulation of data values to remote code execution. In fact, there may be multiple exploitation techniques that lead to possible remote code execution, as is the case with this particular bug. Typically, attackers use remote code execution to install malware, which may have any number of malicious actions, such as keylogging, screen-grabbing and remote access.
IBM X-Force has had product coverage with its network intrusion prevention system (IPS) since reporting this vulnerability back in May 2014, though X-Force hasn’t found any evidence of exploitation of this particular bug in the wild. I have no doubt that it would have fetched six figures on the gray market. The proof of concept IBM X-Force built uses a technique that other people have discovered, too. In fact, it was presented at this year’s Black Hat USA Conference.
In VBScript, array elements are actually Component Object Model (COM) SafeArrays. Each element is a fixed size of 16 bytes, with an initial WORD indicating the Variant type. Under normal circumstances, one will only have control of a maximum of 8 bytes of this data through either the Variant type for double values or for currency values.
| Variant Type (WORD) | Padding (WORD) | Data High (DWORD) | Data Low (DWORD) |
Cutting to the chase, VBScript permits in-place resizing of arrays through the command “redim preserve.” This is where the vulnerability is.
redim preserve arrayname( newsizeinelements )
VBScript.dll contains a runtime evaluation method, CScriptRuntime::Run(VAR *), which farms out the SafeArray redimension task to OleAut32.dll with the SafeArrayRedim(…) function. Essentially, what happens is that fairly early on, SafeArrayRedim() will swap out the old array size (element count) with the resize request. However, there is a code path where, if an error occurs, the size is not reset before returning to the calling function, VBScript!CScriptRuntime::Run().
For VBScript, exploitation of this bug could have been avoided by invalidating the common “On Error Resume Next” VBScript code when the OleAut32 library returns with an error. Since it doesn’t, one can simply rely on this statement to regain script execution and continue to use “corrupted” objects. This VBScript code snippet is extremely common and its presence would not indicate that this vulnerability has been exploited.
Exploitation of Vulnerability
This is the fun part. Although the bug originates in some very old code within the OleAut32 library, I’m approaching exploitation from the perspective of VBScript within Internet Explorer because all versions since 3.0 are vulnerable through this vector.
Exploitation is tricky, partially because array elements are a fixed size. Yet there are two additional issues that complicate exploitation. The first is that there is little opportunity to place arbitrary data where VBScript arrays are stored on the IE heap. The second issue is that, assuming you are now addressing outside the bounds of your VBScript array (Safe Array), you will find the unpleasant enforcement of Variant type compatibility matching.
In the end, the key to exploitation toward reliable code execution was to take advantage of the difference in the element alignment of the arrays (16 bytes) and the alignment of the Windows heap (8 bytes). This provides opportunities to change the Variant type in an element of an adjacent array and to read that content back through the original array reference.
In short, with this kind of memory manipulation available, an attacker can do a number of things. One possibility is to create arbitrary dispatch pointers for VT_DISPATCH or VT_UKNOWN types. This can lead to Data Execution Prevention (DEP) firing if the specified pointer does not correspond to a memory address with execution enabled. There are ways around that, too, but I’ll return to that later. Another possibility would be to use this attack to grab some heap data, but that is a little inconvenient because, again, you run into Variant type compatibility matching. If the location outside of the array boundary that would hold the Variant type is not a known Variant ID or combination on a read operation, or if it is not directly compatible on a write operation, nothing further will happen.
However, again, one can abuse the Variant type of objects in the array. So if attackers start with a BSTR and create a Unicode representation of the data they want another type to point to, it can be used to create objects that can lead to more elaborate exploits. At the time I made the vulnerability discovery, I also happened to run across a blog post hinting that a combination of VT_ARRAY and VT_VARIANT could be useful in this respect. Massaging the data for the VT_VARIANT|VT_ARRAY object permits the use of any virtual address instead of being stuck with the relative addresses of the array boundaries we resized. Furthermore, as we are now dealing with an array of variants, we can use the vartype() command to obtain 16 bits of information from any address we specify. The reason for the 16 bits is just that COM variants max out at 16 bits of data. While we still have to deal with the variant compatibly enforcement, many exciting possibilities now exist.
One of these possibilities permits a data-only attack. The next step for this possibility leverages a memory leak leading to the VBScript class object instance. Content can be left behind in the array data that was never intended to be read. By again changing the variant type of an object in the adjacent array, we can read information that ends up being the point to the VBScript class object. Coincidentally, multiple security researchers may have noticed that both Jscript and VBScript from Microsoft have a check to see whether they are running in a safe mode such as at the command prompt. This check looks at a member of the VBScript (or Jscript) class object to see whether it is in this safe mode. Another great coincidence is that not only can we reliably get to this location in memory using the address leak just discussed, but the nearby data in memory should always pass the variant type compatibility test and permit us to change the value and get code execution indirectly through running unsafe COM objects (think ActiveX) with arbitrary parameters. This is the same attack technique that Yang Yu presented at the Black Hat USA conference this year called the “Vital Point Strike.” Using this approach, which does not use shellcode or more exotic means such as return-oriented programming gadgets, both the EPM sandbox in IE as well as use of Microsoft’s EMET tool are bypassed.
Let’s return to DEP for a moment. There are options here. For example, if there is any read+write+execute (+RWE) memory in a predictable location, we can manipulate objects to point to that memory. Similarly, we could create a large BSTR by pointing a BSTR to the +RWE memory and using the arbitrary write on top of null characters from the +RWE memory to set a large size. The hope is that we could do some in-place modifications with Unicode representations of shellcode. I haven’t tested this out, but it is an interesting idea. Subsequently, we could create arbitrary VT_DISPATCH or VT_UNKNOWN pointers that enable us to point back into the +RWE under our control. However, loading objects or plugins known to create +RWE by default is still a bit of a hassle.
If we have the ability to read arbitrary memory and create arbitrary VT_DISPATCH and VT_UNKNOWN pointers, and we have some ability to control data in memory — either through ordinary heap data we can use with our VBScript and/or data we can touch and change (compatibility testing passes) — we should have no trouble creating Windows API calls. This happens to be another method Yang presented and called “Interdimensional Code Execution.” In fact, using it to disable DEP is possible but somewhat of a waste of an elegant approach for a sledgehammer result.
Hopefully, if you’ve made it this far, you have a pretty good idea how powerful the data attacks facilitated by this bug can be. Again, our disclosure was originally submitted a number of months ago, and while we are not exclusive with the exploitation techniques described, it contributes well toward our goal of describing a significant vulnerability and how it was turned into a viable proof-of-concept attack toward disclosure. We incorporated product coverage for the OLE vulnerability with our network IPS, and so far, the signature we developed has not fired. However, for the attack techniques discussed, I think it is a only matter of time before we see them in the wild.