ブラウザ拡張機能 Pentesting Methodology
Reading time: 40 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を提出してハッキングトリックを共有してください。
基本情報
ブラウザ拡張は JavaScript で書かれ、ブラウザによってバックグラウンドで読み込まれます。それは独自の DOM を持ち、他サイトの DOM と相互作用できます。これは他サイトの機密性、完全性、可用性 (CIA) を侵害する可能性があることを意味します。
主なコンポーネント
拡張機能の構成は視覚化すると分かりやすく、3つのコンポーネントで構成されます。それぞれを詳しく見ていきましょう。
 (1) (1).png)
Content Scripts
各 content script は 単一のウェブページ の DOM に直接アクセスでき、そのため 潜在的に悪意のある入力 にさらされます。ただし、content script が持つ権限は extension core にメッセージを送る能力以外にありません。
Extension Core
extension core は拡張機能のほとんどの権限/アクセスを含みますが、extension core が web コンテンツとやり取りできるのは XMLHttpRequest と content scripts を介した場合のみです。また、extension core はホストマシンへ直接アクセスできません。
Native Binary
拡張機能は ユーザーの完全な権限でホストマシンにアクセスする ネイティブバイナリを許可する場合があります。ネイティブバイナリは Flash などのブラウザプラグインで使われる標準的な Netscape Plugin Application Programming Interface (NPAPI) を通じて extension core とやり取りします。
Boundaries
caution
ユーザーの完全な権限を得るために、攻撃者は extension に content script から extension の core へ、そして extension の core から native binary へ悪意のある入力を渡すよう仕向ける必要があります。
拡張機能の各コンポーネントは互いに 強固な保護境界 で分離されています。各コンポーネントは 別々のオペレーティングシステムプロセス として実行されます。Content scripts と extension cores は、ほとんどの OS サービスからアクセスできない サンドボックスプロセス で実行されます。
さらに、content scripts は関連するウェブページと 別の JavaScript ヒープで実行される ことで分離されています。content script とウェブページは 同じ基盤となる DOM にアクセス できますが、両者は 決して JavaScript ポインタを交換しません。これにより JavaScript 機能の leaking を防ぎます。
manifest.json
A Chrome extension は .crx file extension を持つ ZIP フォルダに過ぎません。拡張機能のコアはフォルダのルートにある manifest.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) に任意にアクセスできます。
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
より多くの URL を含めたり除外したりするには、include_globs と exclude_globs を使用することも可能です。
以下は、the storage API を使用して拡張機能のストレージから message 値を取得したときに、ページに explain ボタンを追加する例の content script です。
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)
})
.png)
このボタンがクリックされると、コンテンツスクリプトはruntime.sendMessage() APIを利用して拡張機能ページにメッセージを送信します。これは、コンテンツスクリプトが直接アクセスできるAPIに制限があり、storage が数少ない例外の一つであるためです。これらの例外を超える機能については、コンテンツスクリプトがやり取りできる拡張機能ページへメッセージが送られます。
warning
ブラウザによっては、コンテンツスクリプトの機能が若干異なることがあります。Chromium-based browsers の機能一覧はChrome Developers documentationに、Firefoxについては主要な情報源としてMDNが参照できます。
また、コンテンツスクリプトはバックグラウンドスクリプトと通信でき、動作を実行したり応答を受け取ったりできる点にも注意してください。
Chromeでコンテンツスクリプトを表示・デバッグするには、Chrome developer tools メニューを Options > More tools > Developer tools から開くか、Ctrl + Shift + I を押します。
デベロッパーツールが表示されたら、Source tabをクリックし、続けてContent Scriptsタブを選択します。これにより、様々な拡張機能で実行中のコンテンツスクリプトを確認し、ブレークポイントを設定して実行フローを追跡できます。
Injected content scripts
tip
Content Scripts は必須ではありません。スクリプトを動的に注入したり、tabs.executeScript を通じてプログラム的にページへ注入することも可能です。これにより、より細かな制御が可能になります。
コンテンツスクリプトをプログラム的に注入するには、拡張機能がスクリプトを注入するページに対する host permissions を持っている必要があります。これらの権限は、拡張のマニフェスト内で要求するか、activeTab を経由して一時的に取得できます。
activeTab を使った拡張機能の例
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- クリック時にJSファイルを注入する:
// 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"],
})
})
- Inject a function(クリック時):
//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,
})
})
スクリプト実行権限の例
// 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 経由
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
経由 service-worker.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
background
コンテンツスクリプトから送信されたメッセージはバックグラウンドページで受信され、拡張機能のコンポーネント間の調整において中心的な役割を果たします。特に、バックグラウンドページは拡張機能のライフタイム全体で持続し、直接ユーザーとやり取りすることなく静かに動作します。独自の Document Object Model(DOM)を持っており、複雑な相互作用や状態管理を可能にします。
主なポイント:
- バックグラウンドページの役割: 拡張機能の中枢として機能し、拡張機能の各部分間の通信と調整を確実にします。
- 永続性: ユーザーには見えない常在する存在であり、拡張機能の機能に不可欠です。
- 自動生成: 明示的に定義されていない場合、ブラウザはバックグラウンドページを自動的に作成します。この自動生成されたページには、拡張機能のmanifestで指定されたすべてのバックグラウンドスクリプトが含まれ、拡張機能のバックグラウンドタスクがシームレスに動作することを保証します。
tip
ブラウザがバックグラウンドページを(明示的に宣言されていない場合に)自動生成してくれる便利さにより、必要なすべてのバックグラウンドスクリプトが統合されて動作し、拡張機能のセットアップが簡素化されます。
バックグラウンドスクリプトの例:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})
It uses runtime.onMessage API to listen to messages. When an "explain" message is received, it uses tabs API to open a page in a new tab.
To debug the background script you could go to the extension details and inspect the service worker, this will open the developer tools with the background script:
Options pages and other
Browser extensions can contain various kinds of pages:
- Action pages are displayed in a drop-down when the extension icon is clicked.
- Pages that the extension will load in a new tab.
- Option Pages: This page displays on top of the extension when clicked. In the previous manifest In my case I was able to access this page in
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjcaor clicking:
.png)
Note that these pages aren't persistent like background pages as they load dynamically content on necessity. Despite this, they share certain capabilities with the background page:
- Communication with Content Scripts: Similar to the background page, these pages can receive messages from content scripts, facilitating interaction within the extension.
- Access to Extension-Specific APIs: These pages enjoy comprehensive access to extension-specific APIs, subject to the permissions defined for the extension.
permissions & host_permissions
permissions and host_permissions are entries from the manifest.json that will indicate which permissions the browser extensions has (storage, location...) and in which web pages.
As browser extensions can be so privileged, a malicious one or one being compromised could allow the attacker different means to steal sensitive information and spy on the user.
Check how these settings work and how they could get abused in:
BrowExt - permissions & host_permissions
content_security_policy
A content security policy can be declared also inside the manifest.json. If there is one defined, it could be vulnerable.
The default setting for browser extension pages is rather restrictive:
script-src 'self'; object-src 'self';
CSP と potential bypasses の詳細については次を参照してください:
Content Security Policy (CSP) Bypass
web_accessible_resources
ウェブページが Browser Extension のページ(例えば .html ページ)にアクセスするには、そのページが manifest.json の web_accessible_resources フィールドに記載されている必要があります。
例えば:
{
...
"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にアクセスできます:
.png)
ただし、manifest.json のパラメータ use_dynamic_url が使用されている場合、この idは動的になる可能性があります。
tip
ここでページが列挙されていても、Content Security Policy によって ClickJackingから保護されている場合があることに注意してください。したがって、ClickJacking攻撃が可能かどうかを確定する前に(frame-ancestors セクションを含めて)確認する必要があります。
これらのページにアクセスできることは、これらのページが潜在的にClickJackingに脆弱であることを意味します:
tip
これらのページをランダムな URL からではなく拡張機能からのみ読み込めるようにすると、ClickJacking 攻撃を防げる可能性があります。
caution
拡張機能の web_accessible_resources にあるページやその他のページは、contacting background scripts(background scripts に接触する) こともできる点に注意してください。したがって、これらのページのいずれかが XSS に脆弱であれば、より大きな脆弱性を招く可能性があります。
さらに、web_accessible_resources に示されたページのみが iframe 内で開けることに注意してください。しかし、新しいタブからは拡張機能 ID が分かれば拡張機能内の任意のページへアクセスすることが可能です。したがって、同じパラメータを悪用する XSS が見つかった場合、そのページが web_accessible_resources に設定されていなくても悪用され得ます。
externally_connectable
ドキュメント(docs)によると、manifest プロパティ "externally_connectable" は runtime.connect および runtime.sendMessage を介して、どの拡張機能やウェブページが接続できるか を宣言します。
- 拡張機能の manifest に
externally_connectableキーが 宣言されていない か、"ids": ["*"]のように宣言されている場合、すべての拡張機能が接続できるが、ウェブページは接続できない。 - 特定の ID が指定されている場合(例:
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"])、それらのアプリケーションのみが接続できます。 - matches が指定されている場合、それらのウェブアプリが接続できるようになります:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- If it's specified as empty:
"externally_connectable": {}, no app or web will be able to connect.
ここに指定される拡張機能やURLが少なければ少ないほど、攻撃対象面は小さくなります。
caution
If a web page vulnerable to XSS or takeover is indicated in externally_connectable, an attacker will be able to send messages directly to the background script, completely bypassing the Content Script and its CSP.
Therefore, this is a very powerful bypass.
Moreover, if the client installs a rouge extension, even if it isn't allowed to communicate with the vulnerable extension, it could inject XSS data in an allowed web page or abuse WebRequest or DeclarativeNetRequest APIs to manipulate requests on a targeted domain altering a page's request for a JavaScript file. (Note that CSP on the targeted page could prevent these attacks). This idea comes from this writeup.
通信の概要
Extension <--> WebApp
content script と web ページ間の通信には通常 post messages が使われます。したがって、web アプリケーション側では通常 window.postMessage への呼び出しが見られ、content script 側では window.addEventListener のようなリスナーが見られます。ただし、extension が web アプリケーションに対して Post Message を送る(そのため web 側はそれを予期する必要がある)か、単に web に新しいスクリプトを読み込ませることもあり得ます。
Inside the extension
通常、拡張内でメッセージを送るには chrome.runtime.sendMessage が使われ(通常は background script で処理される)、受け取って処理するためには chrome.runtime.onMessage.addListener を呼んでリスナーを登録します。
単発のメッセージ送信の代わりに chrome.runtime.connect() を使って持続的な接続を作ることも可能で、以下の例のように メッセージを送受信 するために使えます。
chrome.runtime.connect() example
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
})
バックグラウンドスクリプトから特定のタブにあるコンテンツスクリプトへメッセージを送信することも可能で、その際は chrome.tabs.sendMessage を呼び出し、メッセージ送信先の タブのID を指定する必要があります。
許可された externally_connectable から拡張機能へ
externally_connectable 設定で許可された Webアプリと外部のブラウザ拡張機能は、次の方法でリクエストを送信できます :
chrome.runtime.sendMessage(extensionId, ...
必要に応じてextension IDを記載する。
Native Messaging
バックグラウンドスクリプトはシステム内のバイナリと通信することが可能であり、この通信が適切に保護されていない場合、RCEs のような重大な脆弱性を招く可能性があります。 More on this later.
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
// 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
)
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)
A secure Post Message communication should check the authenticity of the received message, this can be done checking:
event.isTrusted: This is True only if the event was triggered by a users action- The content script might expecting a message only if the user performs some action
- origin domain: might expecting a message only allowlist of domains.
- If a regex is used, be very careful
- Source:
received_message.source !== windowcan be used to check if the message was from the same window where the Content Script is listening.
The previous checks, even if performed, could be vulnerable, so check in the following page potential Post Message bypasses:
Iframe
Another possible way of communication might be through Iframe URLs, you can find an example in:
DOM
This isn't "exactly" a communication way, but the web and the content script will have access to the web DOM. So, if the content script is reading some information from it, trusting the web DOM, the web could modify this data (because the web shouldn't be trusted, or because the web is vulnerable to XSS) and compromise the Content Script.
You can also find an example of a DOM based XSS to compromise a browser extension in:
Content Script ↔︎ Background Script Communication
A Content Script can use the functions runtime.sendMessage() or tabs.sendMessage() to send a one-time JSON-serializable message.
To handle the response, use the returned Promise. Although, for backward compatibility, you can still pass a callback as the last argument.
Sending a request from a content script looks like this:
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
リクエストをextension(通常はbackground script)から送信する。
選択したタブ内のcontent scriptにメッセージを送信する例:
// 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 の イベントリスナー を設定する必要があります。これは content script や extension page からでも同じです。
// 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() は同期的に実行されていました。onMessage イベントハンドラを sendResponse() を非同期で実行するよう変更するには、return true; を必ず含める必要があります。
重要な点として、複数のページが onMessage イベントを受け取る設定になっている場合、特定のイベントに対して最初に sendResponse() を実行したページ のみがレスポンスを有効に返すことができます。同じイベントに対するそれ以降のレスポンスは無視されます。
新しい拡張機能を作成する際は、callbacks より promises を使うことを推奨します。callback を使う場合、sendResponse() は同期コンテキスト内で直接実行された場合、またはイベントハンドラが true を返して非同期処理を示している場合にのみ有効と見なされます。どのハンドラも true を返さない、あるいは sendResponse() がメモリから解放(ガベージコレクション)されると、sendMessage() に渡した callback はデフォルトで呼び出されます。
Native Messaging
ブラウザ拡張は、binaries in the system via stdin と通信することもできます。アプリケーションはその旨を示す 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 は、ブラウザ拡張の background scripts からアプリケーションと通信するために runtime.connectNative() または runtime.sendNativeMessage() に渡される文字列です。path はバイナリへのパスで、type は有効な値が 1 つだけで stdio(stdin と stdout を使用)です。allowed_origins はアクセスできる拡張機能を示し(ワイルドカードは使用できません)。
Chrome/Chromium はこの json を Windows registry や macOS および Linux のいくつかのパスで検索します(詳細は docs を参照)。
tip
ブラウザ拡張でも、この通信を利用するために nativeMessaing permission を宣言しておく必要があります。
以下は、background script が native application にメッセージを送るコードの例です:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In this blog post、native messagesを悪用する脆弱なパターンが提案されています:
- Browser extensionがcontent script用にワイルドカードパターンを持っている。
- Content scriptが
postMessageメッセージをsendMessageを使ってbackground scriptに渡す。 - Background scriptがそのメッセージを
sendNativeMessageを使ってnative applicationに渡す。 - Native applicationがメッセージを危険に処理し、コード実行につながる。
そして、その中で 任意のページからbrowser extensionを悪用してRCEに至る例が説明されています。
Sensitive Information in Memory/Code/Clipboard
もし Browser Extension が 機密情報をメモリ内に保存している と、(特に Windows マシンでは)それが ダンプ され、その情報を 検索 される可能性があります。
したがって、Browser Extension のメモリは 安全とは見なされない ため、credentials や mnemonic phrases のような 機密情報 を 保存すべきではない。
もちろん、コードに機密情報を入れないでください。そうするとそれは public になります。
ブラウザからメモリをダンプするには、プロセスのメモリをダンプ するか、ブラウザ拡張の settings に行き Inspect pop-up をクリック -> Memory セクション -> Take a snaphost -> CTRL+F でスナップショット内を検索して機密情報を探すことができます。
さらに、mnemonic keys やパスワードのような高度に機密性の高い情報は クリップボードにコピーできないようにすべき(少なくとも数秒後にクリップボードから削除する)です。さもないとクリップボードを監視するプロセスがそれらを取得できてしまいます。
Loading an Extension in the Browser
- Download the Browser Extension & unzipped
- Go to
chrome://extensions/and enable theDeveloper Mode - Click the
Load unpackedbutton
In Firefox you go to about:debugging#/runtime/this-firefox and click Load Temporary Add-on button.
Getting the source code from the store
The source code of a Chrome extension can be obtained through various methods. Below are detailed explanations and instructions for each option.
Download Extension as ZIP via Command Line
The source code of a Chrome extension can be downloaded as a ZIP file using the command line. This involves using curl to fetch the ZIP file from a specific URL and then extracting the contents of the ZIP file to a directory. Here are the steps:
- Replace
"extension_id"with the actual ID of the extension. - Execute the following commands:
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 ウェブサイトを使用する
CRX Viewer 拡張機能を使用する
もう1つの便利な方法は、Chrome Extension Source Viewer を使うことです。これはオープンソースプロジェクトで、Chrome Web Store からインストールできます。ビューワーのソースコードはその GitHub repository で入手可能です。
ローカルにインストールされた拡張機能のソースを表示する
Chrome にローカルにインストールされた拡張機能も調べることができます。方法は次のとおりです。
chrome://version/にアクセスし、"Profile Path" フィールドを確認して Chrome のローカルプロファイルディレクトリにアクセスします。- プロファイルディレクトリ内の
Extensions/サブフォルダに移動します。 - このフォルダには、通常読みやすい形式でソースコードを含むすべてのインストール済み拡張機能が格納されています。
拡張機能を特定するには、ID を名前にマッピングできます:
about:extensionsページで Developer Mode を有効にして、各拡張機能の ID を確認します。- 各拡張機能のフォルダ内にある
manifest.jsonファイルには読みやすいnameフィールドが含まれており、拡張機能の特定に役立ちます。
ファイルアーカイバまたはアンパッカを使用する
Chrome Web Store にアクセスして拡張機能をダウンロードします。ファイルは .crx 拡張子になります。ファイル拡張子を .crx から .zip に変更します。WinRAR、7-Zip など任意のファイルアーカイバを使って ZIP の中身を展開してください。
Chrome で Developer Mode を使用する
Chrome を開き、chrome://extensions/ に移動します。右上で "Developer mode" を有効にします。"Load unpacked extension..." をクリックします。拡張機能のディレクトリに移動します。これはソースコードをダウンロードするわけではありませんが、既にダウンロード済みまたは開発中の拡張機能のコードを表示・編集するのに便利です。
Chrome extension manifest dataset
脆弱なブラウザ拡張機能を見つけようとする場合、https://github.com/palant/chrome-extension-manifests-dataset を使い、その manifest ファイルを潜在的に脆弱な箇所についてチェックできます。たとえば、ユーザー数が 25000 を超え、content_scripts を持ち、パーミッションに nativeMessaing が含まれる拡張機能をチェックするには:
# 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')"
Post-exploitation: Forced extension load & persistence (Windows)
Chromium をユーザごとの Preferences を直接編集し、正当な HMACs を偽造してバックドア化するステルス技法。これにより、ブラウザはプロンプトやフラグなしで任意の unpacked extension を受け入れて有効化します。
Forced Extension Load Preferences Mac Forgery Windows
Security Audit Checklist
ブラウザ拡張機能は攻撃対象が比較的限定されているものの、一部には脆弱性やハードニングの余地が存在します。以下は最も一般的なチェック項目です:
-
Limit as much as possible requested
permissions -
Limit as much as possible
host_permissions -
Use a strong
content_security_policy -
Limit as much as possible the
externally_connectable, if none is needed and possible, do not leave it by default, specify{} - If URL vulnerable to XSS or to takeover is mentioned here, an attacker will be able to send messages to the background scripts directly. Very powerful bypass.
-
Limit as much as possible the
web_accessible_resources, even empty if possible. -
If
web_accessible_resourcesis not none, check for ClickJacking - If any communication occurs from the extension to the web page, check for XSS vulnerabilities caused in the communication.
- If Post Messages are used, check for Post Message vulnerabilities.
- If the Content Script access DOM details, check that they aren't introducing a XSS if they get modified by the web
- Make a special emphasis if this communication is also involved in the Content Script -> Background script communication
- If the background script is communicating via native messaging check the communication is secure and sanitized
- Sensitive information shouldn't be stored inside the Browser Extension code
- Sensitive information shouldn't be stored inside the Browser Extension memory
- Sensitive information shouldn't be stored inside the file system unprotected
Browser Extension Risks
- The app https://crxaminer.tech/ analyzes some data like the permissions browser extension requests to give a risk level of using the browser extension.
Tools
Tarnish
- Pulls any Chrome extension from a provided Chrome webstore link.
- manifest.json viewer: simply displays a JSON-prettified version of the extension’s manifest.
- Fingerprint Analysis: Detection of web_accessible_resources and automatic generation of Chrome extension fingerprinting JavaScript.
- Potential Clickjacking Analysis: Detection of extension HTML pages with the web_accessible_resources directive set. These are potentially vulnerable to clickjacking depending on the purpose of the pages.
- Permission Warning(s) viewer: which shows a list of all the Chrome permission prompt warnings which will be displayed upon a user attempting to install the extension.
- Dangerous Function(s): shows the location of dangerous functions which could potentially be exploited by an attacker (e.g. functions such as innerHTML, chrome.tabs.executeScript).
- Entry Point(s): shows where the extension takes in user/external input. This is useful for understanding an extension’s surface area and looking for potential points to send maliciously-crafted data to the extension.
- Both the Dangerous Function(s) and Entry Point(s) scanners have the following for their generated alerts:
- Relevant code snippet and line that caused the alert.
- Description of the issue.
- A “View File” button to view the full source file containing the code.
- The path of the alerted file.
- The full Chrome extension URI of the alerted file.
- The type of file it is, such as a Background Page script, Content Script, Browser Action, etc.
- If the vulnerable line is in a JavaScript file, the paths of all of the pages where it is included as well as these page’s type, and web_accessible_resource status.
- Content Security Policy (CSP) analyzer and bypass checker: This will point out weaknesses in your extension’s CSP and will also illuminate any potential ways to bypass your CSP due to whitelisted CDNs, etc.
- Known Vulnerable Libraries: This uses Retire.js to check for any usage of known-vulnerable JavaScript libraries.
- Download extension and formatted versions.
- Download the original extension.
- Download a beautified version of the extension (auto prettified HTML and JavaScript).
- Automatic caching of scan results, running an extension scan will take a good amount of time the first time you run it. However the second time, assuming the extension hasn’t been updated, will be almost instant due to the results being cached.
- Linkable Report URLs, easily link someone else to an extension report generated by tarnish.
Neto
Project Neto is a Python 3 package conceived to analyse and unravel hidden features of browser plugins and extensions for well-known browsers such as Firefox and Chrome. It automates the process of unzipping the packaged files to extract these features from relevant resources in a extension like manifest.json, localization folders or Javascript and HTML source files.
References
- Thanks to @naivenom for the help with this methodology
- 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/24/attack-surface-of-extension-pages/
- https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/
- 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/mv2/background-pages
- https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/
- https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0
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を提出してハッキングトリックを共有してください。
HackTricks