Uncovering a crazy privilege escalation from Chrome extensions

We discussed this vulnerability during Episode 225 on 20 November 2023

Not something we usually end up covering, but a chrome:// page XSS, and escaping the browser sandbox with an extension.

First the core XSS is pretty straight forward. On ChromeOS the author noticed that downloaded files could not only be accessed through a relatively normal looking file:// URL, but the built-in file manager also used these filesystem:chrome://file-manager/... URLs. Upon inspecting the differences between them they noticed that while the file:// pages would have several restrictions on them, the filesystem:chrome:// schema didn’t seem to have the same restrictions and the JavaScript was running in the chrome://file-manager context, it also had access to the global Mojo object which is used by Chrome for communication between subprocesses like the renderer and the main thread. This was the first vulnerability reported but they did dig into it further to try and escalate.

Their target was getting access to the file-manager’s fileManagerPrivate API/object which is a privileged API only exposed to the ChromeOS file-manager application. Since the filesystem: XSS was running in the chrome://file-manager origin in theory the file-manager would be considered the same origin and could be accessed in same ways, the challenge was actually trying to get a handle to a page with this object. The naive solution of just doing a window.open to open a new chrome://file-manager page and get a handle to it wouldn’t work as the file manager would be reopened as a ChromeOS app and the tab itself would not be useful. The authors solution to this was to leverage an extension:

  1. The XSS running in a filesystem:chrome:// URL would open an uninitialized page: window.open("javascript:0). Saving this as fmWindow the author would get a reference to a new window that hadn’t yet been used to render anything.
  2. Then using an extension with tabs permissions, they could redirect the newly opened tab to view-source:chrome://file-manager which would not get re-opened as a app but would still get the fileManagerPrivate API injected.
  3. Using the fmWindow reference that was captured earlier, they could access the fileManagerPrivate API and do whatever that enables.