Introduction

Chrome browser extensions provide access to several powerful web APIs, giving developers almost limitless functionality that can be built in to their extensions. Web content can be modified, cookies can be changed, and even desktop clients can be controlled. However, if the extension is not set up with the proper permissions, issues can arise allowing malicious websites to take advantage of the extension’s capabilities to wreak havoc. Lets take a look at how improper permissions and the nativeMessaging function can be used to gain access to functions of an extension’s paired desktop client.

Chrome Extensions

There are many things to keep in mind when performing a security review of browser extensions. We won’t be going over everything to look for, but here is a general overview of the extension’s basic workings.

manifest.json

The ‘manifest.json’ file can be seen as how a developer sets up and describes included scripts (service workers and content scripts), host permissions (who can or cannot use the extension’s functions), and which functions the extension utilizes (confusingly called permissions).

image

The top section of our manifest file is self explanitory. Here are the bits we are interested in:

  • default_popup describes the HTML file which creates the look of our extension popup.
  • content_scripts describes the scripts which will be injected into the webpages matching the matches descriptor.
  • host_permissions describes which domains may interract with our extension.
  • permissions describes the APIs our extension will utilize.

Content Scripts

Content scripts are injected into the web pages on domains matching the matches descriptor as mentioned above. These scripts typically interact with the web page itself, as only the content script can interract with the service worker. This allows web pages to communicate with the extension process itself. Typically this communication is done via a set of postMessage function calls.

Service Workers

Service workers are running as their own separate process. They cannot communicate with web pages, but as we will see, can communicate with other extensions or in our case desktop clients.

Permissions

Matches

When setting the permissions for our extension, there are two fields we want to pay attention to. Within our content_scripts section, the matches descriptor is meant to limit which web pages our content script will be injected to. The pattenr matching scheme is defined in the Chrome developer documentation:

image

There are two dangerous scenarios we can imagine here. If an attacker is able to perform subdomain takeover of any kind, when the extension injects the content script into any web page within the subdomain, our web page will be able to interact with that content script.

If the matches descriptor includes any web page (all wildcards), then any web page will be able to interact.

Host Permissions

The host_permissions section is our second line of defense. The extension is allowed to interact with any host matching the URL. This should usually be strictly defined, but wildcards can be utilized if a wide range of hosts is desired.

Interacting With a Desktop Client

Chrome extensions can interact with a desktop client through the use of the nativeMessaging API; this allows the extension to utilize the postMessage API to send messages to the client defined by the service worker.

image

The client must have a manifest.json file and be registered within the computer’s registry (Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts) using the same name:

image

image

The content script must set up a connection with the service worker, and listen for post messages from the web page. Lets take a look at an example content script which sets up a connection to the service worker and listens for messages from the webpage:

image

Let’s go over how this functions in order of operations:

  • The function() call we see on line 22 initiates the connect() function. This is run after the DOM loads, indicated by the run_at descriptor in the manifest file.
  • A connection is set up using chrome.runtime.connect() to communicate with our running service worker.
  • An event listener is set up, listening for messages from the service worker and uses window.post Message to pass the message back to the web page.
  • A second event listener is set up, but this time on the window object, passing the message from the web page to messageHandler, which forwards our message data to the service worker.

Next the service worker must be set up to pass messages to and from our desktop client and the content script:

image

Now let’s go over the order of operations here:

  • An event listener is set up to listen for the incoming connection from the content script.
  • A second event listener is set up to listen for a message from the content script once the connection is made.
  • A connection is initiated with our desktop client com.my_company.my_app
  • A listener is initiated to listen for responses from our desktop client
  • Our message from the content script is sent to the desktop client

Here is a diagram of the flow of data between the web page, extension and desktop client:

image

Finally, let’s take a look at how our web page can send and receive data from the extension. I wrote a simple web page with a button that sends the message, and I write the response to the developer console.

image

How the desktop client receives and resonds to the commands is not very important. In my case, I used the “Lyre” package in Visual Studio Code.

Exploiting Broad Permissions

Using the manifest.json, content script and service worker I showed above, I created an extension and installed it on Chrome. As our permissions allow any domain (due to the wildcards), a malicious website could send commands to the desktop client, and receive the response.

To test this we can simply host the web page we created however we choose (I used a simple python3 http server), browsing to the hosted page. Once we hit the button, our command to get the IP address should be sent to the content script, and the response from the service worker should be forwarded back to our page!

image

Secure Your Extension

Using wildcards in the URL permissions should be avoided. Specifying exact domains to match prevents any web page from utilizing the content script functions, and limits what communications are allowed with the extension.

References

https://developer.chrome.com/docs/extensions

https://book.hacktricks.wiki/en/pentesting-web/browser-extension-pentesting-methodology/index.html

The source code for the extension, web page and client can be found on my github: https://github.com/michaelpoznecki/chrome-extension-research