Browser vulnerabilities have always been serious threats in today's security trends. It's almost becoming too common to see people dropping browser 0days to beef up botnets, or deploying them for "sophisticated" APT-level attacks, etc. Although browser 0days surface more frequently than ever, some of the techniques don't seem to change much. The most common trick you'll see is a heap spray -- this is a way to setup memory by controlling heap allocations, and then place arbitrary code in a predictable place. That way when you control the crash, you can just trick the program to go there and gain code execution. However, this technique has gotten more difficult over the years, so a typical heap spray you see in IE6 and 7 probably won't work against IE8. And a spray in IE 8 probably won't work in IE9 and 10.
Recently, Peter Van Eeckhoutte introduced a new heap spraying technique that works against multiple browsers such as Internet Explorer 8, 9, 10, as well as the latest Firefox. I am pretty much convinced this technique may change the way we write browse exploits for Metasploit, so I decided to port Peter's example to Metasploit as a new function (with his assistance), and show you fellas an example on how to use it.
In this demonstration, I'll just use Internet Explorer 10 on Windows 8. Please make sure to enable script debugging in IE during development. The debugger we'll be using is WinDBG, which can be downloaded here:
|shellcode||The shellcode code to spray. As an example, the input should be in this format: unescape("%u4141%u4141"). Usually this means a ROP, plus the shellcode.|
|offset||Optional. Padding to align the shellcode to some address you want. The default is 0x104 bytes.|
|heapBlockSize||Optional. The allocation size you want. Please note: if this size is too small, your shellcode will not remain at a predicable location in memory. Default is 0x80000.|
|maxAllocs||Optional. Number of allocations. Please note: On IE10, if this is too low, then the shellcode won't be predicable enough, either. The "sweet spot" in our experiment for now seems to be somewhere above 0x500. The default value is 0x350.|
You may also download the test case here to try the heap spraying function:
Examine the Heap Spray
In Internet Explorer, each iteration should generate two allocations that contain our data -- one happens when the substring() function is called, but this one will eventually get freed. The other one is when the data is being assigned to the property, which will trigger a call to SetStringProperty (or SetProperty in IE9), and the data remains in memory. All allocations can be found in the default process heap.
When the heap spray is done, you can simply do this in the debugger:
WinDBG should give you a list of allocations under the default process heap, something like this:
Since the default value for heapBlockSize is 0x80000, and the default for maxAllocs is 0x350, it's evident that our spray is working properly. To dump all these allocations, simply do:
And then you will see something liket his:
Notice all the heap entries end with XXXXXX18, which looks like a predictable pattern. When the allocation pattern is predictable, that indicates your payload should remain in a predicable location, too. Now, to inspect the data, here's what you can do.... let's pick the last entry:
You will see that this points to a field of 0x20s, that means we're looking at the junk padding of the spray. At this point you're probably wondering where the data is, right? One simple thing you can do in WinDBG is go to "View" -> "Memory", and then enter the heap entry address (in our case, again, it's 0x2b108018), and that'll show you a nice memory dump which allows you to scroll up/down to find your data. Like this:
As a reference, the default spray should also land your data at address 0x20302020 in Internet Explorer, but you'll need around 0x500 iterations for IE 10 just to make sure. We have also learned that address 0x0c0d0228 seems to be a reliable place, too. In Firefox, the same data can be seen at 0x20302210. To experiment this yourself, you may simply gather test results and compare them by using mona.py.
"js_property_spray" can also be used to manipulate LFH (Low-Fragmentation Heap) allocations. I recommend to read up Chris Valasek's paper on "Understanding the Low Fragmentation Heap" before trying it out yourself.
To try out this new technique, please make sure to update your Metasploit repository to get the latest changes. If you've never tried Metasploit before, you can download it here: