708 lines
48 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ブラウザ拡張機能のペンテスト方法論
{{#include ../../banners/hacktricks-training.md}}
## 基本情報
ブラウザ拡張機能はJavaScriptで書かれ、ブラウザによってバックグラウンドで読み込まれます。独自の[DOM](https://www.w3schools.com/js/js_htmldom.asp)を持っていますが、他のサイトのDOMと相互作用することができます。これは、他のサイトの機密性、完全性、可用性CIAを危険にさらす可能性があることを意味します。
## 主なコンポーネント
拡張機能のレイアウトは視覚化すると最も良く見え、3つのコンポーネントで構成されています。それぞれのコンポーネントを詳しく見ていきましょう。
<figure><img src="../../images/image (16) (1) (1).png" alt=""><figcaption><p><a href="http://webblaze.cs.berkeley.edu/papers/Extensions.pdf">http://webblaze.cs.berkeley.edu/papers/Extensions.pdf</a></p></figcaption></figure>
### **コンテンツスクリプト**
各コンテンツスクリプトは**単一のウェブページ**のDOMに直接アクセスでき、**潜在的に悪意のある入力**にさらされます。しかし、コンテンツスクリプトは拡張機能のコアにメッセージを送信する能力以外の権限を持っていません。
### **拡張機能コア**
拡張機能コアは、ほとんどの拡張機能の特権/アクセスを含んでいますが、拡張機能コアは[XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)およびコンテンツスクリプトを介してのみウェブコンテンツと相互作用できます。また、拡張機能コアはホストマシンに直接アクセスすることはできません。
### **ネイティブバイナリ**
拡張機能は、**ユーザーの完全な権限でホストマシンにアクセスできるネイティブバイナリ**を許可します。ネイティブバイナリは、Flashや他のブラウザプラグインで使用される標準のNetscapeプラグインアプリケーションプログラミングインターフェース[NPAPI](https://en.wikipedia.org/wiki/NPAPI))を介して拡張機能コアと相互作用します。
### 境界
> [!CAUTION]
> ユーザーの完全な権限を取得するために、攻撃者は拡張機能に悪意のある入力をコンテンツスクリプトから拡張機能のコアに、そして拡張機能のコアからネイティブバイナリに渡すように説得しなければなりません。
拡張機能の各コンポーネントは、**強力な保護境界**によって互いに分離されています。各コンポーネントは**別々のオペレーティングシステムプロセス**で実行されます。コンテンツスクリプトと拡張機能コアは、ほとんどのオペレーティングシステムサービスに利用できない**サンドボックスプロセス**で実行されます。
さらに、コンテンツスクリプトは**別のJavaScriptヒープ**で実行されることにより、関連するウェブページから分離されています。コンテンツスクリプトとウェブページは**同じ基盤となるDOM**にアクセスできますが、2つは**JavaScriptポインタを交換することは決してありません**。これにより、JavaScript機能の漏洩が防止されます。
## **`manifest.json`**
Chrome拡張機能は、単に[.crxファイル拡張子](https://www.lifewire.com/crx-file-2620391)を持つZIPフォルダーです。拡張機能のコアは、フォルダーのルートにある**`manifest.json`**ファイルで、レイアウト、権限、およびその他の設定オプションを指定します。
例:
```json
{
"manifest_version": 2,
"name": "My extension",
"version": "1.0",
"permissions": ["storage"],
"content_scripts": [
{
"js": ["script.js"],
"matches": ["https://example.com/*", "https://www.example.com/*"],
"exclude_matches": ["*://*/*business*"]
}
],
"background": {
"scripts": ["background.js"]
},
"options_ui": {
"page": "options.html"
}
}
```
### `content_scripts`
コンテンツスクリプトは、ユーザーが**一致するページに移動する**たびに**読み込まれ**、この場合は**`https://example.com/*`**式に一致し、**`*://*/*/business*`**正規表現に一致しない任意のページです。これらは**ページ自身のスクリプトのように実行され**、ページの[Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)に対して任意のアクセス権を持っています。
```json
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
```
より多くのURLを含めたり除外したりするために、**`include_globs`** と **`exclude_globs`** を使用することも可能です。
これは、[ストレージAPI](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage)を使用して拡張機能のストレージから`message`値を取得する際に、ページに説明ボタンを追加する例のコンテンツスクリプトです。
```js
chrome.storage.local.get("message", (result) => {
let div = document.createElement("div")
div.innerHTML = result.message + " <button>Explain</button>"
div.querySelector("button").addEventListener("click", () => {
chrome.runtime.sendMessage("explain")
})
document.body.appendChild(div)
})
```
<figure><img src="../../images/image (23).png" alt=""><figcaption></figcaption></figure>
このボタンがクリックされると、コンテンツスクリプトによって拡張ページにメッセージが送信されます。これは、[**runtime.sendMessage() API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage)を利用することによります。コンテンツスクリプトはAPIへの直接アクセスに制限があり、`storage`が数少ない例外の一つです。これらの例外を超える機能については、コンテンツスクリプトが通信できる拡張ページにメッセージが送信されます。
> [!WARNING]
> ブラウザによって、コンテンツスクリプトの機能は若干異なる場合があります。Chromiumベースのブラウザの場合、機能リストは[Chrome Developers documentation](https://developer.chrome.com/docs/extensions/mv3/content_scripts/#capabilities)で入手可能で、Firefoxの場合は[MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis)が主な情報源となります。\
> また、コンテンツスクリプトはバックグラウンドスクリプトと通信する能力があり、これによりアクションを実行し、応答を返すことができます。
Chromeでコンテンツスクリプトを表示およびデバッグするには、オプション > その他のツール > デベロッパーツールからChromeデベロッパーツールメニューにアクセスするか、Ctrl + Shift + Iを押します。
デベロッパーツールが表示されたら、**ソースタブ**をクリックし、次に**コンテンツスクリプト**タブをクリックします。これにより、さまざまな拡張機能から実行中のコンテンツスクリプトを観察し、実行フローを追跡するためのブレークポイントを設定できます。
### 注入されたコンテンツスクリプト
> [!TIP]
> **コンテンツスクリプトは必須ではない**ことに注意してください。**動的に**スクリプトを**注入**したり、**プログラム的に注入**することも可能です。これは実際により**細かい制御**を提供します。
コンテンツスクリプトをプログラム的に注入するには、拡張機能がスクリプトを注入するページに対して[ホスト権限](https://developer.chrome.com/docs/extensions/reference/permissions)を持っている必要があります。これらの権限は、拡張機能のマニフェスト内で**要求する**か、[**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab)を通じて一時的に取得することができます。
#### activeTabベースの拡張機能の例
```json:manifest.json
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
```
- **クリックでJSファイルをインジェクトする:**
```javascript
// content-script.js
document.body.style.backgroundColor = "orange"
//service-worker.js - Inject the JS file
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"],
})
})
```
- **クリック時に関数を注入する**:
```javascript
//service-worker.js - Inject a function
function injectedFunction() {
document.body.style.backgroundColor = "orange"
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: injectedFunction,
})
})
```
#### スクリプト権限の例
```javascript
// service-workser.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
excludeMatches: ["*://*/*business*"],
js: ["contentScript.js"],
},
])
// Another example
chrome.tabs.executeScript(tabId, { file: "content_script.js" })
```
より多くのURLを含めたり除外したりするために、**`include_globs`** と **`exclude_globs`** を使用することも可能です。
### コンテンツスクリプト `run_at`
`run_at` フィールドは **JavaScriptファイルがウェブページに注入されるタイミング** を制御します。推奨されるデフォルト値は `"document_idle"` です。
可能な値は次のとおりです:
- **`document_idle`**: 可能な限り
- **`document_start`**: `css` からのファイルの後、しかし他のDOMが構築される前や他のスクリプトが実行される前。
- **`document_end`**: DOMが完了した直後ですが、画像やフレームなどのサブリソースが読み込まれる前。
#### `manifest.json` を介して
```json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
```
**`service-worker.js`**を介して
```javascript
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
```
### `background`
コンテンツスクリプトによって送信されたメッセージは、**background page**によって受信され、拡張機能のコンポーネントを調整する中心的な役割を果たします。特に、background pageは拡張機能のライフタイムを通じて持続し、直接的なユーザーの操作なしに静かに動作します。独自のDocument Object Model (DOM)を持ち、複雑な相互作用と状態管理を可能にします。
**重要なポイント**:
- **Background Pageの役割:** 拡張機能の神経中枢として機能し、拡張機能のさまざまな部分間の通信と調整を確保します。
- **持続性:** ユーザーには見えないが、拡張機能の機能に不可欠な常に存在するエンティティです。
- **自動生成:** 明示的に定義されていない場合、ブラウザは自動的にbackground pageを作成します。この自動生成されたページには、拡張機能のマニフェストに指定されたすべてのバックグラウンドスクリプトが含まれ、拡張機能のバックグラウンドタスクのシームレスな操作を確保します。
> [!TIP]
> 明示的に宣言されていない場合にブラウザがbackground pageを自動生成することによって提供される便利さは、すべての必要なバックグラウンドスクリプトが統合され、機能することを保証し、拡張機能のセットアッププロセスを簡素化します。
Example background script:
```js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})
```
それは、メッセージをリッスンするために [runtime.onMessage API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) を使用します。`"explain"` メッセージを受信すると、[tabs API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) を使用して新しいタブでページを開きます。
バックグラウンドスクリプトをデバッグするには、**拡張機能の詳細に移動してサービスワーカーを検査**することができます。これにより、バックグラウンドスクリプトを含む開発者ツールが開きます:
<figure><img src="https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/browser-extension-pentesting-methodology/broken-reference" alt=""><figcaption></figcaption></figure>
### オプションページとその他
ブラウザ拡張機能にはさまざまな種類のページが含まれることがあります:
- **アクションページ**は、**拡張機能のアイコン**がクリックされたときにドロップダウンで表示されます。
- 拡張機能が**新しいタブで読み込む**ページ。
- **オプションページ**:このページは、クリックすると拡張機能の上に表示されます。前のマニフェストでは、`chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` でこのページにアクセスできました。または、クリックすることで:
<figure><img src="../../images/image (24).png" alt="" width="375"><figcaption></figcaption></figure>
これらのページは、必要に応じて動的にコンテンツを読み込むため、バックグラウンドページのように永続的ではないことに注意してください。それにもかかわらず、これらはバックグラウンドページと特定の機能を共有しています:
- **コンテンツスクリプトとの通信**:バックグラウンドページと同様に、これらのページはコンテンツスクリプトからメッセージを受信でき、拡張機能内での相互作用を促進します。
- **拡張機能固有のAPIへのアクセス**これらのページは、拡張機能に定義された権限に従って、拡張機能固有のAPIへの包括的なアクセスを享受します。
### `permissions` & `host_permissions`
**`permissions`** と **`host_permissions`** は、ブラウザ拡張機能が持つ**どの権限**(ストレージ、位置情報など)と**どのウェブページ**であるかを示す `manifest.json` のエントリです。
ブラウザ拡張機能は非常に**特権的**であるため、悪意のあるものや侵害されたものは、攻撃者に**機密情報を盗んだりユーザーを監視したりするためのさまざまな手段を提供する可能性があります**。
これらの設定がどのように機能し、どのように悪用される可能性があるかを確認してください:
{{#ref}}
browext-permissions-and-host_permissions.md
{{#endref}}
### `content_security_policy`
**コンテンツセキュリティポリシー**は、`manifest.json` 内でも宣言できます。定義されている場合、それは**脆弱**である可能性があります。
ブラウザ拡張機能ページのデフォルト設定はかなり制限されています:
```bash
script-src 'self'; object-src 'self';
```
CSPや潜在的なバイパスに関する詳細情報は、次を確認してください
{{#ref}}
../content-security-policy-csp-bypass/
{{#endref}}
### `web_accessible_resources`
ウェブページがブラウザ拡張のページ、例えば`.html`ページにアクセスするためには、このページが`manifest.json`の**`web_accessible_resources`**フィールドに記載されている必要があります。\
例えば:
```javascript
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
```
これらのページは次のようなURLでアクセス可能です:
```
chrome-extension://<extension-id>/message.html
```
公共拡張機能では、**extension-idがアクセス可能**です:
<figure><img src="../../images/image (1194).png" alt="" width="375"><figcaption></figcaption></figure>
ただし、`manifest.json`パラメータ**`use_dynamic_url`**が使用されている場合、この**idは動的**になる可能性があります。
> [!TIP]
> ここにページが記載されていても、**Content Security Policy**のおかげで**ClickJacking**から**保護されている**可能性があることに注意してください。したがって、ClickJacking攻撃が可能かどうかを確認する前に、それをチェックする必要がありますframe-ancestorsセクション
これらのページにアクセスできることは、これらのページが**潜在的に脆弱なClickJacking**であることを意味します:
{{#ref}}
browext-clickjacking.md
{{#endref}}
> [!TIP]
> これらのページが拡張機能によってのみ読み込まれ、ランダムなURLによっては読み込まれないようにすることで、ClickJacking攻撃を防ぐことができます。
> [!CAUTION]
> **`web_accessible_resources`**からのページや拡張機能の他のページも**バックグラウンドスクリプトに連絡する**ことができることに注意してください。したがって、これらのページのいずれかが**XSS**に対して脆弱である場合、より大きな脆弱性を引き起こす可能性があります。
>
> さらに、**`web_accessible_resources`**に示されたページはiframe内でのみ開くことができますが、新しいタブからは拡張機能IDを知っていれば拡張機能内の任意のページにアクセスすることが可能です。したがって、同じパラメータを悪用するXSSが見つかった場合、ページが**`web_accessible_resources`**に設定されていなくても悪用される可能性があります。
### `externally_connectable`
[**docs**](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable)によると、`"externally_connectable"`マニフェストプロパティは、**どの拡張機能とウェブページがあなたの拡張機能に接続できるか**を宣言します。これは[runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect)および[runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage)を介して行われます。
- **`externally_connectable`**キーが拡張機能のマニフェストに**宣言されていない**場合、または**`"ids": ["*"]`**として宣言されている場合、**すべての拡張機能が接続できますが、ウェブページは接続できません**。
- **特定のIDが指定されている**場合、例えば`"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`のように、**そのアプリケーションのみ**が接続できます。
- **matches**が指定されている場合、これらのウェブアプリは接続できるようになります:
```json
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
```
- 空で指定されている場合: **`"externally_connectable": {}`**、アプリやウェブは接続できません。
ここで示されている **拡張機能とURL** が少ないほど、**攻撃面は小さく**なります。
> [!CAUTION]
> **`externally_connectable`** に **XSSまたはテイクオーバーに脆弱なウェブページ** が示されている場合、攻撃者は **バックグラウンドスクリプトに直接メッセージを送信** でき、コンテンツスクリプトとそのCSPを完全にバイパスすることができます。
>
> したがって、これは **非常に強力なバイパス** です。
>
> さらに、クライアントが不正な拡張機能をインストールした場合、たとえそれが脆弱な拡張機能と通信することが許可されていなくても、**許可されたウェブページにXSSデータを注入** したり、**`WebRequest`** または **`DeclarativeNetRequest`** APIを悪用して、ターゲットドメインのリクエストを操作し、ページの **JavaScriptファイル** のリクエストを変更することができます。ターゲットページのCSPがこれらの攻撃を防ぐ可能性があることに注意してください。このアイデアは [**この書き込みから**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability) 来ています。
## コミュニケーションの概要
### 拡張機能 <--> ウェブアプリ
コンテンツスクリプトとウェブページ間で通信するために、通常はポストメッセージが使用されます。したがって、ウェブアプリケーションでは通常 **`window.postMessage`** 関数への呼び出しが見られ、コンテンツスクリプトでは **`window.addEventListener`** のようなリスナーが見られます。ただし、拡張機能は **ポストメッセージを送信してウェブアプリケーションと通信** することもでき(したがってウェブはそれを期待する必要があります)、単にウェブに新しいスクリプトを読み込ませることもできます。
### 拡張機能内
通常、**`chrome.runtime.sendMessage`** 関数が拡張機能内でメッセージを送信するために使用され(通常は `background` スクリプトによって処理されます)、それを受信して処理するためにリスナーが **`chrome.runtime.onMessage.addListener`** を呼び出して宣言されます。
**`chrome.runtime.connect()`** を使用して、単一のメッセージを送信する代わりに持続的な接続を持つことも可能で、次の例のように **メッセージを送信** および **受信** するために使用できます。
<details>
<summary><code>chrome.runtime.connect()</code> の例</summary>
```javascript
var port = chrome.runtime.connect()
// Listen for messages from the web page
window.addEventListener(
"message",
(event) => {
// Only accept messages from the same window
if (event.source !== window) {
return
}
// Check if the message type is "FROM_PAGE"
if (event.data.type && event.data.type === "FROM_PAGE") {
console.log("Content script received: " + event.data.text)
// Forward the message to the background script
port.postMessage({ type: "FROM_PAGE", text: event.data.text })
}
},
false
)
// Listen for messages from the background script
port.onMessage.addListener(function (msg) {
console.log("Content script received message from background script:", msg)
// Handle the response message from the background script
})
```
</details>
特定のタブにあるコンテンツスクリプトにメッセージを送信することも可能で、**`chrome.tabs.sendMessage`**を呼び出す際にメッセージを送信する**タブのID**を指定する必要があります。
### 許可された `externally_connectable` から拡張機能へ
`externally_connectable` 設定で許可された**Webアプリと外部ブラウザ拡張機能**は、次のようにリクエストを送信できます:
```javascript
chrome.runtime.sendMessage(extensionId, ...
```
必要な場合は、**拡張ID**を言及する必要があります。
### ネイティブメッセージング
バックグラウンドスクリプトは、システム内のバイナリと通信することが可能であり、この通信が適切に保護されていない場合、**RCEなどの重大な脆弱性にさらされる可能性があります**。[この後で詳しく説明します](#native-messaging)。
```javascript
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
```
## Web **↔︎** Content Script Communication
**content scripts**が動作する環境とホストページが存在する環境は**分離**されており、**隔離**が確保されています。この隔離にもかかわらず、両者はページの**Document Object Model (DOM)**、つまり共有リソースと相互作用する能力を持っています。ホストページが**content script**と通信するため、またはcontent scriptを介して拡張機能と間接的に通信するためには、両者がアクセス可能な**DOM**を通信チャネルとして利用する必要があります。
### Post Messages
```javascript:content-script.js
// This is like "chrome.runtime.sendMessage" but to maintain the connection
var port = chrome.runtime.connect()
window.addEventListener(
"message",
(event) => {
// We only accept messages from ourselves
if (event.source !== window) {
return
}
if (event.data.type && event.data.type === "FROM_PAGE") {
console.log("Content script received: " + event.data.text)
// Forward the message to the background script
port.postMessage(event.data.text)
}
},
false
)
```
```javascript:example.js
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)
```
安全なPost Message通信は、受信したメッセージの信頼性を確認する必要があります。これは以下を確認することで行えます
- **`event.isTrusted`**: これは、イベントがユーザーのアクションによってトリガーされた場合にのみTrueになります。
- コンテンツスクリプトは、ユーザーが何らかのアクションを実行した場合にのみメッセージを期待するかもしれません。
- **origin domain**: メッセージを期待する場合は、許可リストのドメインのみを許可するかもしれません。
- 正規表現が使用される場合は、非常に注意が必要です。
- **Source**: `received_message.source !== window`を使用して、メッセージが**コンテンツスクリプトがリスニングしている同じウィンドウ**からのものであるかどうかを確認できます。
前述のチェックは、実施されていても脆弱である可能性があるため、次のページで**潜在的なPost Messageバイパス**を確認してください:
{{#ref}}
../postmessage-vulnerabilities/
{{#endref}}
### Iframe
別の通信方法として**Iframe URLs**を通じて行うことが考えられます。例は以下にあります:
{{#ref}}
browext-xss-example.md
{{#endref}}
### DOM
これは「正確に」通信方法ではありませんが、**ウェブとコンテンツスクリプトはウェブDOMにアクセスできます**。したがって、**コンテンツスクリプト**がそこから情報を読み取っている場合、**ウェブDOMを信頼している**と、ウェブはこのデータを**変更する可能性があります**ウェブは信頼されるべきではないため、またはウェブがXSSに脆弱であるためし、**コンテンツスクリプトを危険にさらす**可能性があります。
**DOMベースのXSSを使用してブラウザ拡張を危険にさらす**例も以下にあります:
{{#ref}}
browext-xss-example.md
{{#endref}}
## コンテンツスクリプト **↔︎** バックグラウンドスクリプト通信
コンテンツスクリプトは、[**runtime.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage) **または** [**tabs.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/tabs#method-sendMessage)を使用して、**一度限りのJSONシリアライズ可能な**メッセージを送信できます。
**レスポンス**を処理するには、返された**Promise**を使用します。ただし、後方互換性のために、最後の引数として**コールバック**を渡すこともできます。
**コンテンツスクリプト**からリクエストを送信するのは次のようになります:
```javascript
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
```
**拡張機能**からリクエストを送信します(通常は**バックグラウンドスクリプト**)。選択したタブのコンテンツスクリプトにメッセージを送信する方法の例:
```javascript
// From https://stackoverflow.com/questions/36153999/how-to-send-a-message-between-chrome-extension-popup-and-content-script
;(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
})
const response = await chrome.tabs.sendMessage(tab.id, { greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
```
受信側では、メッセージを処理するために[**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **イベントリスナー**を設定する必要があります。これは、コンテンツスクリプトまたは拡張ページから見ると同じように見えます。
```javascript
// From https://stackoverflow.com/questions/70406787/javascript-send-message-from-content-js-to-background-js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(
sender.tab
? "from a content script:" + sender.tab.url
: "from the extension"
)
if (request.greeting === "hello") sendResponse({ farewell: "goodbye" })
})
```
例で強調されたように、**`sendResponse()`** は同期的に実行されました。`sendResponse()` の非同期実行のために `onMessage` イベントハンドラーを修正するには、`return true;` を組み込むことが不可欠です。
重要な考慮事項は、複数のページが `onMessage` イベントを受信するように設定されているシナリオでは、**特定のイベントに対して最初に `sendResponse()`** を実行したページだけが、効果的に応答を提供できるということです。同じイベントに対するその後の応答は考慮されません。
新しい拡張機能を作成する際は、コールバックよりもプロミスを優先すべきです。コールバックの使用に関しては、`sendResponse()` 関数は、同期コンテキスト内で直接実行される場合、またはイベントハンドラーが `true` を返すことによって非同期操作を示す場合にのみ有効と見なされます。どのハンドラーも `true` を返さない場合や、`sendResponse()` 関数がメモリから削除された場合(ガーベジコレクションされた場合)、`sendMessage()` 関数に関連付けられたコールバックがデフォルトでトリガーされます。
## ネイティブメッセージング
ブラウザ拡張機能は、**stdinを介してシステム内のバイナリと通信することも可能です**。アプリケーションは、次のようなjsonを示すjsonをインストールする必要があります:
```json
{
"name": "com.my_company.my_application",
"description": "My Application",
"path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
"type": "stdio",
"allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}
```
`name` は [`runtime.connectNative()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-connectNative) または [`runtime.sendNativeMessage()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-sendNativeMessage) に渡される文字列で、ブラウザ拡張のバックグラウンドスクリプトからアプリケーションと通信するために使用されます。 `path` はバイナリへのパスで、1つの有効な `type` は stdiostdin と stdout を使用)であり、 `allowed_origins` はアクセスできる拡張機能を示します(ワイルドカードは使用できません)。
Chrome/Chromium は、この JSON をいくつかの Windows レジストリや macOS および Linux のいくつかのパスで検索します(詳細は [**docs**](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging) を参照)。
> [!TIP]
> ブラウザ拡張は、この通信を使用できるようにするために `nativeMessaing` 権限を宣言する必要があります。
これは、ネイティブアプリケーションにメッセージを送信するバックグラウンドスクリプトコードの例です:
```javascript
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
```
[**このブログ投稿**](https://spaceraccoon.dev/universal-code-execution-browser-extensions/)では、ネイティブメッセージを悪用する脆弱なパターンが提案されています:
1. ブラウザ拡張機能は、コンテンツスクリプトのためのワイルドカードパターンを持っています。
2. コンテンツスクリプトは、`sendMessage`を使用してバックグラウンドスクリプトに`postMessage`メッセージを渡します。
3. バックグラウンドスクリプトは、`sendNativeMessage`を使用してネイティブアプリケーションにメッセージを渡します。
4. ネイティブアプリケーションはメッセージを危険に扱い、コード実行につながります。
その中で、**ブラウザ拡張機能を悪用して任意のページからRCEに移行する例が説明されています**。
## メモリ/コード/クリップボード内の機密情報
ブラウザ拡張機能が**メモリ内に機密情報を保存している場合**、これは**ダンプ**される可能性があり特にWindowsマシンで、この情報が**検索**される可能性があります。
したがって、ブラウザ拡張機能のメモリは**安全とは見なされるべきではなく**、**機密情報**(資格情報やニーモニックフレーズなど)は**保存されるべきではありません**。
もちろん、**コード内に機密情報を置かないでください**、それは**公開される**からです。
ブラウザからメモリをダンプするには、**プロセスメモリをダンプ**するか、ブラウザ拡張機能の**設定**に行き、**`Inspect pop-up`**をクリック -> **`Memory`**セクション -> **`Take a snapshot`**を選択し、**`CTRL+F`**でスナップショット内の機密情報を検索します。
さらに、ニーモニックキーやパスワードのような非常に機密性の高い情報は、**クリップボードにコピーされることを許可すべきではありません**(または少なくとも数秒以内にクリップボードから削除するべきです)なぜなら、クリップボードを監視しているプロセスがそれらを取得できるからです。
## ブラウザに拡張機能を読み込む
1. **ブラウザ拡張機能をダウンロード**し、解凍します。
2. **`chrome://extensions/`**に移動し、`Developer Mode`を**有効にします**。
3. **`Load unpacked`**ボタンをクリックします。
**Firefox**では、**`about:debugging#/runtime/this-firefox`**に移動し、**`Load Temporary Add-on`**ボタンをクリックします。
## ストアからソースコードを取得する
Chrome拡張機能のソースコードは、さまざまな方法で取得できます。以下に各オプションの詳細な説明と手順を示します。
### コマンドラインを使用してZIPとして拡張機能をダウンロード
Chrome拡張機能のソースコードは、コマンドラインを使用してZIPファイルとしてダウンロードできます。これは、`curl`を使用して特定のURLからZIPファイルを取得し、その後ZIPファイルの内容をディレクトリに抽出することを含みます。手順は以下の通りです
1. `"extension_id"`を拡張機能の実際のIDに置き換えます。
2. 次のコマンドを実行します:
```bash
extension_id=your_extension_id # Replace with the actual extension ID
curl -L -o "$extension_id.zip" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
unzip -d "$extension_id-source" "$extension_id.zip"
```
### CRX Viewerウェブサイトを使用する
[https://robwu.nl/crxviewer/](https://robwu.nl/crxviewer/)
### CRX Viewer拡張機能を使用する
もう一つの便利な方法は、オープンソースプロジェクトであるChrome Extension Source Viewerを使用することです。これは[Chrome Web Store](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=en)からインストールできます。ビューワーのソースコードはその[GitHubリポジトリ](https://github.com/Rob--W/crxviewer)で入手可能です。
### ローカルにインストールされた拡張機能のソースを表示する
ローカルにインストールされたChrome拡張機能も検査できます。方法は以下の通りです
1. `chrome://version/`にアクセスし、「Profile Path」フィールドを見つけて、Chromeのローカルプロファイルディレクトリに移動します。
2. プロファイルディレクトリ内の`Extensions/`サブフォルダに移動します。
3. このフォルダには、通常は読みやすい形式のソースコードを持つすべてのインストールされた拡張機能が含まれています。
拡張機能を特定するには、IDを名前にマッピングできます
- `about:extensions`ページで開発者モードを有効にして、各拡張機能のIDを確認します。
- 各拡張機能のフォルダ内の`manifest.json`ファイルには、拡張機能を特定するのに役立つ読みやすい`name`フィールドが含まれています。
### ファイルアーカイバまたはアンパッカーを使用する
Chrome Web Storeにアクセスして拡張機能をダウンロードします。ファイルは`.crx`拡張子を持っています。ファイルの拡張子を`.crx`から`.zip`に変更します。任意のファイルアーカイバWinRAR、7-Zipなどを使用してZIPファイルの内容を抽出します。
### Chromeで開発者モードを使用する
Chromeを開き、`chrome://extensions/`に移動します。右上で「開発者モード」を有効にします。「解凍された拡張機能を読み込む...」をクリックします。拡張機能のディレクトリに移動します。これはソースコードをダウンロードするものではありませんが、すでにダウンロードまたは開発された拡張機能のコードを表示および修正するのに便利です。
## Chrome拡張機能マニフェストデータセット
脆弱なブラウザ拡張機能を見つけるために、[https://github.com/palant/chrome-extension-manifests-dataset](https://github.com/palant/chrome-extension-manifests-dataset)を使用して、マニフェストファイルに潜在的な脆弱性の兆候がないか確認できます。たとえば、25000人以上のユーザーを持つ拡張機能、`content_scripts`、および権限`nativeMessaging`を確認するには:
```bash
# Query example from https://spaceraccoon.dev/universal-code-execution-browser-extensions/
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"
```
## セキュリティ監査チェックリスト
ブラウザ拡張機能は**限られた攻撃面**を持っていますが、その中には**脆弱性**や**強化の可能性**が含まれている場合があります。以下は最も一般的なものです:
- [ ] **要求される** **`permissions`** を可能な限り制限する
- [ ] **`host_permissions`** を可能な限り制限する
- [ ] **強力な** **`content_security_policy`** を使用する
- [ ] **`externally_connectable`** を可能な限り制限する。必要がない場合はデフォルトで残さず、**`{}`** を指定する
- [ ] ここに**XSSまたは乗っ取りに脆弱なURL**が記載されている場合、攻撃者は**バックグラウンドスクリプトに直接メッセージを送信できる**。非常に強力なバイパスです。
- [ ] **`web_accessible_resources`** を可能な限り制限する。可能であれば空にする。
- [ ] **`web_accessible_resources`** がない場合、[**ClickJacking**](browext-clickjacking.md)を確認する
- [ ] **拡張機能**から**ウェブページ**への**通信**が発生する場合、[**XSS**](browext-xss-example.md) **脆弱性**が通信によって引き起こされていないか確認する。
- [ ] Post Messagesが使用されている場合、[**Post Messageの脆弱性**](../postmessage-vulnerabilities/)**を確認する。**
- [ ] **Content ScriptがDOMの詳細にアクセスする**場合、ウェブによって**変更される**と**XSSを導入していないか**確認する
- [ ] この通信が**Content Script -> バックグラウンドスクリプト通信**にも関与している場合は特に強調する
- [ ] バックグラウンドスクリプトが**ネイティブメッセージング**を介して通信している場合、通信が安全でサニタイズされているか確認する
- [ ] **機密情報は**ブラウザ拡張機能の**コード内に保存すべきではない**
- [ ] **機密情報は**ブラウザ拡張機能の**メモリ内に保存すべきではない**
- [ ] **機密情報は****ファイルシステムに無防備に保存すべきではない**
## ブラウザ拡張機能のリスク
- アプリ [https://crxaminer.tech/](https://crxaminer.tech/) は、ブラウザ拡張機能が要求する権限などのデータを分析し、ブラウザ拡張機能の使用リスクレベルを提供します。
## ツール
### [**Tarnish**](https://thehackerblog.com/tarnish/)
- 提供されたChromeウェブストアリンクから任意のChrome拡張機能を取得します。
- [**manifest.json**](https://developer.chrome.com/extensions/manifest) **ビューワー**拡張機能のマニフェストのJSON整形バージョンを表示します。
- **フィンガープリンター分析** [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) の検出とChrome拡張機能フィンガープリンティングJavaScriptの自動生成。
- **潜在的なClickjacking分析** [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) ディレクティブが設定された拡張機能のHTMLページの検出。これらはページの目的に応じてClickjackingに脆弱である可能性があります。
- **権限警告ビューワー**ユーザーが拡張機能をインストールしようとしたときに表示されるすべてのChrome権限プロンプト警告のリストを表示します。
- **危険な関数**攻撃者によって悪用される可能性のある危険な関数の場所を示しますinnerHTML、chrome.tabs.executeScriptなど
- **エントリポイント**:拡張機能がユーザー/外部入力を受け取る場所を示します。これは拡張機能の表面積を理解し、悪意のあるデータを拡張機能に送信する潜在的なポイントを探すのに役立ちます。
- 危険な関数とエントリポイントスキャナーは、生成されたアラートに対して以下を持っています:
- アラートを引き起こした関連コードスニペットと行。
- 問題の説明。
- コードを含む完全なソースファイルを表示するための「ファイルを表示」ボタン。
- アラートが発生したファイルのパス。
- アラートが発生したファイルの完全なChrome拡張機能URI。
- それがどのようなファイルであるか(バックグラウンドページスクリプト、コンテンツスクリプト、ブラウザアクションなど)。
- 脆弱な行がJavaScriptファイルにある場合、それが含まれているすべてのページのパスとこれらのページのタイプ、[web_accessible_resource](https://developer.chrome.com/extensions/manifest/web_accessible_resources) ステータス。
- **コンテンツセキュリティポリシーCSPアナライザーおよびバイパスチェッカー**これにより、拡張機能のCSPの弱点が指摘され、ホワイトリストに登録されたCDNなどによるCSPのバイパスの潜在的な方法が明らかになります。
- **既知の脆弱なライブラリ**:これは[Retire.js](https://retirejs.github.io/retire.js/)を使用して、既知の脆弱なJavaScriptライブラリの使用をチェックします。
- 拡張機能とフォーマットされたバージョンをダウンロード。
- 元の拡張機能をダウンロード。
- 拡張機能の美化されたバージョンをダウンロード自動整形されたHTMLとJavaScript
- スキャン結果の自動キャッシュ。拡張機能のスキャンを初めて実行する際にはかなりの時間がかかります。しかし、拡張機能が更新されていない限り、2回目は結果がキャッシュされるため、ほぼ瞬時に完了します。
- リンク可能なレポートURL。簡単に他の人にTarnishによって生成された拡張機能レポートへのリンクを提供します。
### [Neto](https://github.com/elevenpaths/neto)
プロジェクトNetoは、FirefoxやChromeなどの有名なブラウザのブラウザプラグインや拡張機能の隠れた機能を分析し、解明するために考案されたPython 3パッケージです。`manifest.json`、ローカリゼーションフォルダー、またはJavaScriptおよびHTMLソースファイルなどの関連リソースからこれらの機能を抽出するために、パッケージ化されたファイルを解凍するプロセスを自動化します。
## 参考文献
- **この方法論に関する助けを提供してくれた** [**@naivenom**](https://twitter.com/naivenom) **に感謝します**
- [https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing](https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing)
- [https://palant.info/2022/08/10/anatomy-of-a-basic-extension/](https://palant.info/2022/08/10/anatomy-of-a-basic-extension/)
- [https://palant.info/2022/08/24/attack-surface-of-extension-pages/](https://palant.info/2022/08/24/attack-surface-of-extension-pages/)
- [https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/)
- [https://help.passbolt.com/assets/files/PBL-02-report.pdf](https://help.passbolt.com/assets/files/PBL-02-report.pdf)
- [https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts)
- [https://developer.chrome.com/docs/extensions/mv2/background-pages](https://developer.chrome.com/docs/extensions/mv2/background-pages)
- [https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/](https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/)
- [https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0](https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0)
{{#include ../../banners/hacktricks-training.md}}