In Search of is_mojojs_enabled_ ---[ 1. Exploiting Chromium 101 Web browsers remain the most most commonly exploited vector of compromise. But escaping a modern sandbox remains a hard problem. Usually, a full exploit chain requires (at minimum) a series of at least two security bugs. The first stage exploit that allows arbitrary code execution, followed by a second bug in the browser process that is reachable from the sandbox over Inter-Process Communication (IPC). The Chromium Project has been moving away from "Legacy" IPC for several years now, preferring its more robust successor; Mojo. Mojo is a well designed communication protocol, but even in the most modern Chromium browsers (at time of writing 112), it is flawed in its attempts to be both a flexible IPC martialling protocol and an adaptive development tool. ---[ 2. MojoJS Bindings Mojo ingests protocols defined as .mojom files, and automatically generates binding code in both the browser's native C++ language, as well as protocol-friendly Javascript. The latter allows in-renderer interpreted scripts to bind and interface directly with Mojo's native message buffer interface, facilitating rich user experiences with minimal interactions in message parsing. It handles the secure martialling of arguments at both ends, minimizing the scope for programmer error in complex message packing and unpacking. However, it is precisely these developer-convenient bindings which are regularly exploited by attackers. Those rich Javascript-friendly MojoJS bindings are an attractive target for exploit developers. As such, any browser Elevation of Privilege which requires a mojo interface, is significantly easier if those martialling routines are simply exposed for the attacker's script to call into. By default, however, those bindings are not available. But they are present, lying dormant behind a feature flag. Developers wishing to use or test their scripts can simply initialise the browsing session with the --enable-mojo-js flag. This in turn will enable the feature and expose the mojo bindings. Ultimately, access to the MojoJS interface bindings is controlled by a single boolean in the .data section. The symbol for that boolean is "is_mojojs_enabled_". It is for this reason that following the initial remote code execution within the renderer process, it is common that attackers will seek the offset and change the value of is_mojojs_enabled_ to facilitate their second stage exploit. Therefore, most Chromium exploits tend to follow the same pattern: [] Gain in-renderer (sandboxed) remote code execution [] Enable MojoJS bindings by setting is_mojojs_enabled_ to True [] Exploit an exposed browser mojo interface [] Elevate out of the sandbox [] Profit ---[ 3. Finding is_mojojs_enabled_ Chromium based browsers, however, are truly massive. And the offset to the required boolean differs across builds and vendors. Version 112.0.5615.138 of Google's Chrome browser, for example stores the value at Virtual Address 0x18c2079c9 (offset 0xc206bc9 from image base). Whereas Microsoft Edge 112.0.1722.48 has the value at 0x18dfe92ed (0xdfe72ed from base). Finding this offset using IDA or debuggers can be a manual and tedious process and, in the case of IDA Pro, can involve hours of parsing the instructions of tends of thousands of functions. Fortunately, it is possible to script the identification by leveraging the way in which feature flags are stored in Chromium. ---[ 3.1 Chromium feature flags Locating this value in an automated fashion is non-trivial. It resides in automatically generated code within Blink (the browser's rendering engine). The generation is orchestrated by a number of scripts, which create code based on a template file located in /third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl At compile time, this produces native C++ code which is output to .cc and .h files out/Debug/gen/third_party/blink/renderer/platform/runtime_enabled_features.cc out/Debug/gen/third_party/blink/renderer/platform/runtime_enabled_features.h The generated header file contains a large number of booleans within the blink:: namespace, including the flag controlling the enablement of MojoJS: 411 bool is_middle_click_autoscroll_enabled_; 412 bool is_mobile_layout_theme_enabled_; [413] bool is_mojo_js_enabled_; 414 bool is_mojo_js_test_enabled_; 415 bool is_navigate_event_cancelable_traversals_enabled_; 416 bool is_navigate_event_commit_behavior_enabled_; Here on line [413] is the flag that we are interested in. But this alone does not give us the boolean's final location within the binary. For that we need to find a reference to it. Fortunately, the autogenerated C++ code contains a static array of structures containing pointers to both the feature name, and the address of the flag. The following is taken from the generated code: 2119 static const struct { 2120 const char* name; 2121 bool* setting; 2122 } kFeatures[] = { 2123 {"AOMAriaRelationshipProperties", &is_aom_aria_relationship_properties_enabled_}, 2124 {"AbortSignalAny", &is_abort_signal_any_enabled_}, .... 2474 {"MobileLayoutTheme", &is_mobile_layout_theme_enabled_}, [2475] {"MojoJS", &is_mojo_js_enabled_}, 2476 {"MojoJSTest", &is_mojo_js_test_enabled_}, You will notice that line [2475] has the structure entry that we are interested in. Static consts are all linked into the .rdata section, so this gives us everything that we need to find the flag! In memory, the kFeatures entry will contain two adjacent pointers. The first to the string "MojoJS", the second to the flag. We can therefore scan the .rdata section for the string "MojoJS\0". Once we have the offset of this string, we then need to scan the .rdata section once again for references to that pointer (adjusted for the Virtual Address; Base Address + RVA). The next eight bytes (or four bytes for 32-bit builds) will be a pointer to the boolean! 18d1ea920 [ const char* name (18d1ecd7b) ][ bool* setting (18dfe92ed) ] / \ 18dfe92ed / [ is_mojo_js_enabled_ ] / 18d1ecd7b [ "MojoJS\0" ] Now that we have the pieces in place we can craft a script to automate this for every Chromium-based browser which uses this construct in Blink. ---[ 4. The Script The script resulting from this research can be found at https://github.com/kryc/find_is_mojojs_enabled