Thinking Outside the JIT Compiler
Engineers explore architecture and security mechanisms for Thinking Outside the JIT Compiler.
Summary
## Overview
Alibaba security engineer presented exploitation of JavaScript engine vulnerabilities in WebKit (JavaScriptCore) used by Safari and iOS, bypassing structure ID randomization mitigation. Problem: JavaScriptCore JIT compiler (DFG and FTL tiers) contains subtle bugs enabling type confusion exploits that leak object memory layout and enable arbitrary code execution. Mitigation: structure ID randomization (introduced early 2020) encodes object property layout in random structure IDs, preventing attackers from predicting internal object layout and crafting crafted objects matching legitimate structures. Research contribution: generic bypass technique using JavaScript engine features (toString optimization, Symbol handling, prototype manipulation) to leak structure IDs despite randomization, enabling reliable exploitation. Attack chain: leak structure IDs of known object shapes → construct fake objects with leaked structure IDs → trigger JIT compiler type confusion → build exploit primitives (address leaks, memory read/write) → achieve arbitrary code execution on iOS/macOS. Practical impact: reliably exploits WebKit vulnerabilities post-mitigation, demonstrating that randomization-based defenses require multiple layers and can be defeated through side-channel information leakage.
## JavaScript Object Layout and Structure ID Randomization
**Internal Object Representation**: JavaScriptCore represents JavaScript objects using hidden structure IDs encoding object shape (which properties exist, their order, types). JSObject layout: (1) JSCell header containing structure ID (unique identifier for object shape); (2) indexing type (array access method); (3) JSType (internal type designation); (4) state flags; (5) butterfly pointer (indirect storage for properties/array elements); (6) property values for in-line properties. Property lookup: structure ID indexes into structure table to determine property offsets, enabling efficient access. Without randomization: structure IDs allocated sequentially (IDs 0, 1, 2, 3...), allowing attacker to predict structure IDs by creating objects in known order and inferring ID assignments. Vulnerability: attacker creates specific sequence of objects with known properties, calculates expected structure IDs, constructs fake objects that engine treats as legitimate based on structure ID matching.
**Randomization Implementation**: Structure ID randomization adds random entropy to structure IDs, making sequential prediction impossible. Challenge: engine must validate structure IDs when accessing object properties—if attacker uses invalid structure ID, engine either crashes or rejects invalid pointer. Defender's dilemma: structure ID validation requires checking against valid structure pointer table; if check is expensive, optimization removed (enabling bypass); if check is thorough, performance degrades. Engine hides actual structure pointers behind indices, attempting to prevent leaking valid structure IDs through information disclosure.
## Structure ID Leak Techniques and Bypass Methods
**Side-Channel via toString() Optimization**: Many built-in JavaScript prototypes implement toString() method for string conversion. Key observation: toString() implementation may require accessing structure information internally (for functions, it may return source code). Bypass technique: (1) create fake object with controlled memory layout; (2) set butterfly pointer in fake object to point to target object's internal fields; (3) call toString() on prototype through fake object; (4) engine interprets fake object's fields as real properties, leaks internal structure information without triggering JIT optimization removal. Attack mechanism: function toString() implementation in some cases requires source code pointer access; by faking function object layout, attacker leaks memory addresses and internal pointers.
**Symbol Description Bypass**: JavaScript Symbols include optional descriptions stored as properties. Bypass: create fake Symbol object with controlled internal layout, call toString() expecting engine to read description field; engine reads attacker-controlled location in memory, leaks pointers. Advantage over direct memory read: operation appears to be legitimate JavaScript operation (toString call), potentially evading dynamic analysis or emulation-based detection.
**Generic Bypass via Type Confusion**: Abuse JIT compiler type assumptions: DFG compiler optimizes based on observed types (type inference from previous operations); if operation type changes unexpectedly, optimization produces incorrect code. Attack: trigger type confusion causing JIT to assume wrong object type, read/write beyond expected object bounds. Without structure ID validation preventing type confusion, attacker leaks arbitrary values from memory layout.
## Exploitation Chain: From Information Leak to Arbitrary Execution
**Exploit Steps**: (1) Leak structure ID of target object type (using toString/Symbol method); (2) construct fake object with leaked structure ID, setting butterfly pointer to control target field access; (3) trigger JIT compiler optimization on fake object to build type confusion primitive; (4) use type confusion to read arbitrary memory (leak function pointers, vtables, return addresses); (5) construct ROP/JOP gadget chain or modify code pointers; (6) achieve arbitrary code execution as JavaScriptCore process (iOS app sandbox context). Limitations: requires JavaScript context within app (web content, JavaScript execution), cannot directly exploit kernel or OS; however, many iOS apps embed WebKit or use JavaScriptCore, enabling in-app exploitation. iOS mitigation (pointer authentication, code signing) reduces practical ROP gadget availability; JOP (indirect jumps through data pointers) more reliable if code pointers can be leaked and corrupted.
**Unreliability Handling**: Structure ID randomization attempts to make exploitation probabilistic—even after bypass, probability of correct structure ID on first attempt ~1% (if entropy is log2(100) bits). Exploit resilience: attempt structure ID guess, if crashes detected, restart and retry with different ID candidate. Web context: can trigger exploit repeatedly until successful, making probabilistic exploit viable. Native app context: multiple crashes may be detected, limiting retry attempts.
Related talks
Videos·24 min
Dave KENNEDY
Presenters detail vulnerability discovery and exploitation in Dave KENNEDY - Thinking outside of the box [EN].
Microsoft Security Response Center (MSRC)·43 min
Industry experts analyze emerging threats surrounding BlueHat Oct 23. S09: Thinking Outside The (Dead)Box.
BSides Knoxville·42 min
Jay Paz
Jay Paz - Thinking outside the security box: Assembling non traditional security teams.


