Electron Desktop Apps
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Electron combines a local backend (with NodeJS) and a frontend (Chromium), although tt lacks some the security mechanisms of modern browsers.
Usually you might find the electron app code inside an .asar
application, in order to obtain the code you need to extract it:
In the source code of an Electron app, inside packet.json
, you can find specified the main.js
file where security configs ad set.
Electron has 2 process types:
Main Process (has complete access to NodeJS)
Renderer Process (should have NodeJS restricted access for security reasons)
A renderer process will be a browser window loading a file:
Settings of the renderer process can be configured in the main process inside the main.js file. Some of the configurations will prevent the Electron application to get RCE or other vulnerabilities if the settings are correctly configured.
The electron application could access the device via Node apis although it can be configure to prevent it:
nodeIntegration
- is off
by default. If on, allows to access node features from the renderer process.
contextIsolation
- is on
by default. If off, main and renderer processes aren't isolated.
preload
- empty by default.
sandbox
- is off by default. It will restrict the actions NodeJS can perform.
Node Integration in Workers
nodeIntegrationInSubframes
- is off
by default.
If nodeIntegration
is enabled, this would allow the use of Node.js APIs in web pages that are loaded in iframes within an Electron application.
If nodeIntegration
is disabled, then preloads will load in the iframe
Example of configuration:
Some RCE payloads from here:
Modify the start-main configuration and add the use of a proxy such as:
If you can execute locally an Electron App it's possible that you could make it execute arbitrary javascript code. Check how in:
macOS Electron Applications InjectionIf the nodeIntegration is set to on, a web page's JavaScript can use Node.js features easily just by calling the require()
. For example, the way to execute the calc application on Windows is:
The script indicated in this setting is loaded before other scripts in the renderer, so it has unlimited access to Node APIs:
Therefore, the script can export node-features to pages:
If contextIsolation
is on, this won't work
The contextIsolation introduces the separated contexts between the web page scripts and the JavaScript Electron's internal code so that the JavaScript execution of each code does not affect each. This is a necessary feature to eliminate the possibility of RCE.
If the contexts aren't isolated an attacker can:
Execute arbitrary JavaScript in renderer (XSS or navigation to external sites)
Overwrite the built-in method which is used in preload or Electron internal code to own function
Trigger the use of overwritten function
RCE?
There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code:
Electron contextIsolation RCE via preload codeElectron contextIsolation RCE via Electron internal codeElectron contextIsolation RCE via IPCIf there are restrictions applied when you click a link you might be able to bypass them doing a middle click instead of a regular left click
For more info about this examples check https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 and https://benjamin-altpeter.de/shell-openexternal-dangers/
hen deploying an Electron desktop application, ensuring the correct settings for nodeIntegration
and contextIsolation
is crucial. It's established that client-side remote code execution (RCE) targeting preload scripts or Electron's native code from the main process is effectively prevented with these settings in place.
Upon a user interacting with links or opening new windows, specific event listeners are triggered, which are crucial for the application's security and functionality:
These listeners are overridden by the desktop application to implement its own business logic. The application evaluates whether a navigated link should be opened internally or in an external web browser. This decision is typically made through a function, openInternally
. If this function returns false
, it indicates that the link should be opened externally, utilizing the shell.openExternal
function.
Here is a simplified pseudocode:
Electron JS security best practices advise against accepting untrusted content with the openExternal
function, as it could lead to RCE through various protocols. Operating systems support different protocols that might trigger RCE. For detailed examples and further explanation on this topic, one can refer to this resource, which includes Windows protocol examples capable of exploiting this vulnerability.
Examples of Windows protocol exploits include:
Disabling contextIsolation
enables the use of <webview>
tags, similar to <iframe>
, for reading and exfiltrating local files. An example provided demonstrates how to exploit this vulnerability to read the contents of internal files:
Further, another method for reading an internal file is shared, highlighting a critical local file read vulnerability in an Electron desktop app. This involves injecting a script to exploit the application and exfiltrate data:
If the chromium used by the application is old and there are known vulnerabilities on it, it might be possible to to exploit it and obtain RCE through a XSS. You can see an example in this writeup: https://blog.electrovolt.io/posts/discord-rce/
Supposing you found a XSS but you cannot trigger RCE or steal internal files you could try to use it to steal credentials via phishing.
First of all you need to know what happen when you try to open a new URL, checking the JS code in the front-end:
The call to openInternally
will decide if the link will be opened in the desktop window as it's a link belonging to the platform, or if will be opened in the browser as a 3rd party resource.
In the case the regex used by the function is vulnerable to bypasses (for example by not escaping the dots of subdomains) an attacker could abuse the XSS to open a new window which will be located in the attackers infrastructure asking for credentials to the user:
Electronegativity is a tool to identify misconfigurations and security anti-patterns in Electron-based applications.
Electrolint is an open source VS Code plugin for Electron applications that uses Electronegativity.
nodejsscan to check for vulnerable third party libraries
Electro.ng: You need to buy it
In https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s you can find a lab to exploit vulnerable Electron apps.
Some commands that will help you will the lab:
More researches and write-ups about Electron security in https://github.com/doyensec/awesome-electronjs-hacking
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)