RCE using XSS in Electron applications

TL;DR

Notable 1.8.4 allows XSS via crafted Markdown text, with resultant remote code execution (because nodeIntegration in webPreferences is true).

About Notable

Notable is a markdown-based note-taking app that is developed using Electron framework. Notable was originally released as open-source but newer versions of it are no longer open-source.

Electron and Node Integration

Electron is a framework that enables you to create desktop applications with JavaScript, HTML, and CSS. These applications can then be packaged to run directly on macOS, Windows, or Linux, or distributed via the Mac App Store or the Microsoft Store.

From a development perspective, an Electron application is essentially a Node.js application.

The main script specifies the entry point of your Electron application (in our case, the main.js file) that will run the Main process. Typically, the script that runs in the Main process controls the lifecycle of the application, displays the graphical user interface and its elements, performs native operating system interactions, and creates Renderer processes within web pages. An Electron application can have only one Main process.

Each window can optionally be granted with full access to Node.js API through the nodeIntegration preference.

const { app, BrowserWindow } = require('electron')function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadFile('index.html')
}

Exploitation

After installing Notable we reverse-engineered the app.asar file which reveals that nodeIntegration is set to true.

After trying some simple XSS payloads we can see that the markdown parser does not sanitize the input properly, hence we are able to run arbitrary javascript code.

As nodeIntegration is set to true we have access to Node.js API. We can use the shell module in Electron to call an external URI. For PoC we are calling calc.exe using the following payload.

<a onmouseover="try{ const {shell} = require('electron'); shell.openExternal('file:C:/Windows/System32/calc.exe') }catch(e){alert(e)}">Harmless Link</a>

This calc.exe could have been any malicious payload local or remote which could have given the attacker entire access to the victim’s system. It is also possible to remove user interaction completely so that the payload is executed as soon as the markdown file is parsed.

Disclosure Timeline

  • 2020–04–24 Disclosure to developer
  • 2020–04–24 Developer informed that this will be fixed in the upcoming builds.
  • 2020–12–04 Developer confirmed that as of v1.9.0-beta it is still unfixed but will be fixed in future builds.
  • 2020–12–10 Public disclosure of the vulnerability.

References

I like computers and offensive security.