Browser Exploitation on Windows — Chakra/ChakraCore (CVE-2019-0567)
Last updated: 2026-04-10
Primary source: Connor McGarr — 3-part blog series (2022-03-11)
Related: Type Confusion, Mitigations
Tags:user-mode,browser,jit,type-confusion,cfg,acg,chakra,cve-2019-0567
Summary
CVE-2019-0567 is a type confusion vulnerability in Microsoft’s Chakra/ChakraCore JavaScript JIT compiler. Connor McGarr’s 3-part series documents end-to-end modern browser exploitation on Windows: JIT type confusion → R/W primitive → ASLR/DEP/CFG bypass → ACG bypass → code execution in Edge. This page provides a conceptual framework and key techniques; see the raw sources for step-by-step details.
Environment
- Target: Microsoft Edge (pre-V8 Chakra engine) + ChakraCore shell (
ch.exe) - Windows version: Windows 10 1703 (pre-KB4480961 patch)
- CVE-2019-0567: Type confusion in Chakra JIT
- CVE-2017-8637: ACG bypass (patched Windows 10 RS4+)
- Mitigations present: ASLR, DEP, CFG, ACG, CIG (no child processes), CET absent
JIT Type Confusion Fundamentals
Why JIT is an Attack Surface
JIT compilers must:
- Observe JavaScript value types at runtime
- Emit optimized machine code assuming those types stay stable
- Insert type guards (bailout checks) when assumptions might be violated
The attack: violate type assumptions without triggering the guard → JIT emits code that treats one type as another → type confusion.
Chakra-Specific: Array Type System
Chakra tracks array element types for optimization:
JavascriptNativeIntArray → elements are 32-bit integers
JavascriptNativeFloatArray → elements are 64-bit floats
JavascriptArray → elements are JS Values (boxed, 64-bit)
A type confusion from NativeIntArray → JavascriptArray means code treats 32-bit int storage as 64-bit JS Value pointers → addrof (leak object address) and fakeobj (create fake object at address) primitives.
CVE-2019-0567 Root Cause
The JIT compiler incorrectly infers that two arrays of different types are the same type, allowing a native (unboxed) array to be treated as an object array. Accessing elements of the confused array reads raw memory bytes as JavaScript object pointers → addrof/fakeobj primitives.
Exploit Primitive Ladder
1. Type confusion (CVE-2019-0567)
→ addrof(object) — read object's kernel address as JS integer
→ fakeobj(address) — treat raw memory address as JS object
2. addrof + fakeobj → AAR/AAW (arbitrary address read/write)
→ Craft fake DataView/TypedArray object at known address
→ Manipulate internal buffer pointer → read/write arbitrary process memory
3. ASLR defeat
→ Use AAR to read function pointers from DOM object vtables → leak module base
4. DEP bypass (ROP)
→ Use AAW to write ROP chain to stack → redirect stack pivot
→ Or: overwrite return address
5. CFG bypass
→ Valid indirect call targets via CFG bitmap lookup
→ Find "safe" CFG-allowed function that acts as trampoline
→ Route ROP through CFG-valid jump
6. Code execution (ChakraCore)
→ Write shellcode to RWX JIT page (present in ChakraCore without ACG)
→ Jump to shellcode via ROP
7. ACG bypass (Edge — CVE-2017-8637, patched RS4+)
→ Edge enforces ACG (no dynamic code generation from renderer)
→ Bypass: Content process → injecting into broker or other non-ACG process
→ Or: Use NtMapViewOfSection to map pre-existing executable pages
Key JavaScript Exploit Primitives
// addrof: leak address of a JavaScript object
function addrof(obj) {
// ... type confusion: read obj as raw integer
return address_as_float;
}
// fakeobj: create JavaScript "object" at arbitrary address
function fakeobj(addr) {
// ... type confusion: treat raw address as object pointer
return fake_object;
}
// AAR using fake DataView:
function read64(addr) {
// Create fake DataView pointing buffer to addr
// Read 8 bytes via DataView.getBigInt64()
}
// AAW using fake DataView:
function write64(addr, value) {
// Same technique, DataView.setBigInt64()
}
Windows-Specific Mitigations (Edge Context)
| Mitigation | Impact | Bypass |
|---|---|---|
| ASLR | All module bases randomized | Leak via vtable pointer from known heap object |
| DEP | No exec on data pages | ROP chain |
| CFG | Validates indirect call targets | Find CFG-valid trampoline; Windows 10 1703 has weaker CFG |
| ACG | No dynamic code pages | CVE-2017-8637 (patched RS4+); write to existing JIT pages |
| CIG | Code integrity in renderer | Block unsigned DLL injection |
| No child proc | Cannot spawn child processes | Use existing processes; inject into broker |
ChakraCore vs Chakra/Edge Differences
| Aspect | ChakraCore (ch.exe) | Chakra (Edge) |
|---|---|---|
| JIT pages | RWX (no ACG) | W^X enforced (ACG) |
| Child processes | Allowed | Blocked |
| CIG | Not enforced | Enforced |
| Symbols | Available (open source) | No symbols |
Development strategy: exploit in ChakraCore first → port to Edge in Part 3.
Resources
- Connor McGarr — Parts 1, 2, 3 (2022-03-11) — connormcgarr.github.io/type-confusion-part-{1,2,3}
- Bruno Keith — “Attacking Edge Through the JavaScript Compiler” — Nullcon 2019
- Google Project Zero — CVE-2019-0567 issue tracker
- Perception Point — CVE-2019-0539 writeup (sister vulnerability)
- ChakraCore source: github.com/chakra-core/ChakraCore (commit
331aa39)
