At the beginning of March we published a blog post analyzing CVE-2015-0311, a Use-After-Free vulnerability in Adobe Flash Player, and we outlined how to exploit it on Windows 7 SP1 machines. As we mentioned at the end of that article, the exploitation process explained there doesn't apply to more recent versions of Windows like Windows 8.1 with Update 3, because of a new exploit mitigation technology called Control Flow Guard (CFG).
CFG – which was introduced by Microsoft in Windows 8.1 Update 3 in November 2014 – adds a check before every indirect call in the code in order to verify that the destination address of that call is one of the locations identified as “safe” at compile time. If that check fails at runtime, the program detects an attempt to subvert the normal execution flow and exits immediately. Prior to the existence of Control Flow Guard, leveraging a vulnerability like a Use-After-Free into arbitrary memory read & write primitives – as we did with CVE-2015-0311 – used to mean circumvention of ASLR and DEP and ultimately reliable code execution.
The interesting thing about Control Flow guard is that now, even having those powerful read & write primitives, being able to gain code execution may require a noteworthy additional effort. It turns out that the Flash version for Internet Explorer 11 that is integrated into Windows 8.1 Update 3 is compiled with Control Flow Guard enabled, so the well-known technique of overwriting the vtable of an object with a pointer to attacker-controlled data and then calling a virtual function on that object will not work.
Let's find look at how we can bypass Control Flow Guard when exploiting Adobe Flash Player on Internet Explorer 11 running on Windows 8.1 Update 3. This post assumes that you have already read part one, so we are going straight to the point where we are ready to hijack the execution flow of the browser process.
A brief overview of Control Flow Guard
On non-CFG versions of Flash, this is the code that dereferences the overwritten vtable when calling the toString() method on a Vector object, as shown in the previous blog post: