Back in February 2018, Google's Project Zero went public with a Microsoft Edge bug that Redmond couldn't fix in time for its next patch release. Now, the Google researcher - Ivan Fratric - has provided a detailed technical explanation of the problem and says Microsoft's fix might not be adequate.
Arbitrary Code Guard (ACG) is designed to prevent code being dynamically modified, and had its most recent enhancements in March 2017.
Google reveals Edge bug that Microsoft has had trouble fixingREAD MORE
Fratric explained the problem in this post last Thursday: “When ACG is applied to a Microsoft Edge Content Process, it makes it impossible to allocate new executable memory within a process or modify existing executable memory. The goal of this is to make it more difficult for an attacker who already gained some capabilities in the browser’s Content Process to execute arbitrary code.”
Because JIT is incompatible with ACG, instead of running JIT as part of the Edge Content Process, Microsoft pulled the JIT Engine into its own process.
That, the white paper explained, lets the Content Process execute the JIT code “without violating the dynamic code policy.”
The other key to the attack surface is the Control Flow Guard (CFG), designed to protect against memory corruption vulnerabilities. The Fratric paper notes that one vector here is that “returns aren’t protected, so overwriting a return address is all that’s needed for a successful bypass. Normally, in order to be able to overwrite a return address on the stack, an attacker first needs to know where stack is. Chakra bytecode removes this requirement by including opcodes that can be used to read & write to the stack”.
There’s a full walk-through of various memory mappings and process interactions before we get to the attack scenario set out in the white paper:
- Attacker observes the addresses for the JIT allocations and predicts the address of the next one;
- Attacker unmaps the corresponding JIT section
- Attacker calls
VirtualAlloc()to reclaim the memory, but this time with
- Attacker writes their payload to a newly allocated location;
- Attacker waits until the JIT server makes the memory region executable. After this, an attacker can simply transfer control flow to the code written in step 4.
As is so often the case, the fix wasn't as hard as Microsoft feared: Redmond just had to remove the
There’s a proof-of-concept here, and its only assumption was that “an attacker already managed to get a memory read/write primitive in the Content Process through an unrelated vulnerability.” ®