Almost every Patch Tuesday cycle contains one bulletin that (for convenience) rolls up multiple Internet Explorer vulnerabilities into a single bulletin. February's Patch Tuesday cumulative IE bulletin ( MS15-009 ) included a fix for a particularly interesting vulnerability that could be used to bypass one of the key anti-exploit technologies in use today, address space layout randomization (ASLR). This vulnerability was designated CVE-2015-0071 . To be used in an attack, this vulnerability must be combined with another one that is capable of actually running code on the affected machines. In attacks seen by iSIGHT , this has been paired with an Adobe Flash vulnerability ( CVE-2014-9163 ), which was fixed in December. This vulnerability was found in the jscript9.dll module. To analyze this vulnerability, I examined this file (version 9.0.8112.1645) on a Windows 7, 32-bit system.Examining the patched and unpatched versions of this DLL, we found a modification im thefunction.

Figure 1. Patched SetProperty function

Figure 2. Unpatched SetProperty function

In the patched version, the function Js::JavascriptRegExpConstructors::EnsureValues is called, and only then is the property's value set. The unpatched version does not call this particular function at all. The functioncan show us how to fully analyze this vulnerability. To do this, we need to explain some data structures dealing with regular expressions. This page from the MSDN Library explains data structures that store the results of regular expressions. When the JavaScript syntax is used, it has the following properties:

Figure 3. Expression properties

Input - the source string

lastMatch - the match string

$1-$9 - the sub-match string.

0x24: pInputString (the source string)

0x28: startIndex (beginning of the lastMatch string in the pInputString's index)

0x2c: length (the lastMatch string length)

0x30: isNeedUpdate (whether or not to update the related field)

0x40: pUnmatchString

0x44: pUnSearchString

0x48: pLastMatchString (the address of the matching string)

0x4c: $1 (the submatch 1 string)

0x00: pVtable

0x08: length (the string length)

0x0c: pString (pointer to the string array's starting address)Demonstration

var src = "Please send mail to george@contoso.com and someone@example.com. Thanks!"; pattern = “(george)”; var re = new RegExp( pattern ); re.exec( src ); alert(RegExp.$1);

We will only focus on the following properties, as they are relevant for this analysis:How does Internet Explorer implement this? It does so in the DLL file. It uses the following structure named Js::JavascriptRegExpConstructor, which represents the global object RegExp which is used to store a regular expression's matching results.All of the strings above have the following structure (named Js::SingleCharString):Let's consider the following sample code (the test string is one frequently used by Microsoft in demonstrating regular expressions):This is the contents of the memory after re.exec has finished running:

Figure 4. Memory contents after re.exec command

pInputString points to the string "Please send mail...". lastMatch.startIndex is 0x14, and lastMatch.length is 0x06. isNeedUpdate is True. The other fields still have their initial value. For example, $1 is set to the null string. Only the three fields noted above were modified. After alert(RegExp.$1) has run, the contents of the memory are as follows:

Figure 5. Memory contents after alert(RegExp.$1)

When we reference RegExp.$1, it will call GetProperty like so:

Figure 6. GetProperty command

It checks if isNeedUpdate is false. If yes, the update is finished, so the function will return. Otherwise, it will go to step #2 to update the file. EnsureValues use the pInputString, beginIndex, length and re.exec results to compute the other fields of the JavascriptRegExpConstructor

EnsureValues first uses UnifiedRegex::RegexPattern::GetGroup to get $1-related information. It return startIndex, length, and startIndex. Representation $1 begin address in the pInputString, length is the $1 length. Call Js::SubString::New to create Js::SingleCharString. The parameters of this are pInputString, startIndex, and length. The return of this function is $1_address. Set the $1_address at JavascriptRegExpConstructor related field. Here, it is 0x4c.

var src = "Please send mail to george@contoso.com and someone@example.com. Thanks!"; pattern = “(george)”; var re = new RegExp( pattern ); re.exec( src ); RegExp.input = "123456" alert(RegExp.$1);

When regexp.exec finishes, the function just stores the inputString (we call this right_inputString) and the lastmatch string’s index and length. When we set RegExp.input, RegExp just modified the pInputString field (we call this error_inputString), and didn't modify the other fields. When we use RegExp.$1 and read the property, RegExp will use the inputString(error_inputString) field to compute the other fields. If the error_inputString length is smaller than the $1.startIndex+$1.length, when we reference RegExp.$1, it can read error_inputString out of bounds.

To return the proper value, GetProperty calls EnsureValues to update fields related to JavascriptRegExpConstructor. We can see that isNeedUpdate is set false, and the $1-$9 fields are set. Let’s look in some detail at EnsureValues. This function is quite complex, so we just consider the parts related to this vulnerability:With RegExp.$1 as an example, let’s look at how EnsureValues computes for $1.Now that we have understanding of EnsureValues, we can see how the vulnerability is triggered, and how Microsoft patched it.Consider the following code:Before we run alert(RegExp.$1), if we add a statement before it (the bolded code), jscript9.dll will call Js::JavascriptRegExpConstructor::SetProperty. In the unpatched version, it only change the pinputString field of the global RegExp object. Next we reference RegExp.$1. Because isneedUpdate is true, the Js::JavascriptRegExpConstructor::GetProperty function will call EnsureValues to compute the rest fields. Because the inputString is changed to (errorinputString), this will be used to compute the related fields. If the value of $1.startIndex + $1.length(UnifiedRegex::RegexPattern::GetGroup) is bigger than the inputString, we can use the value of $1 to trigger an out of bounds read, bypassing ASLR.The cause of this vulnerability may be as simple as developers forgetting to call EnsureValues in the SetProperty function.While this vulnerability could pose a risk used with other vulnerabilities, it’s worth noting that Microsoft has already patched these issues as part of their regular Patch Tuesday cycles. Users with up-to-date systems would not be at risk, which highlights the importance of keeping a system's software up to date.