Методологія pentesting розширень браузера

Reading time: 26 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Базова інформація

Browser extensions написані на JavaScript і завантажуються браузером у фоновому режимі. Вони мають свій DOM, але можуть взаємодіяти з DOM інших сайтів. Це означає, що вони можуть ставити під загрозу конфіденційність, цілісність і доступність (CIA) інших сайтів.

Основні компоненти

Структура розширення легше сприймається при візуалізації і складається з трьох компонентів. Розглянемо кожен компонент докладніше.

http://webblaze.cs.berkeley.edu/papers/Extensions.pdf

Content Scripts

Each content script має прямий доступ до DOM окремої веб-сторінки і таким чином піддається потенційно шкідливому вводу. Однак content script не має дозволів, окрім можливості відправляти повідомлення до extension core.

Extension Core

Extension core містить більшість привілеїв/доступу розширення, але extension core може взаємодіяти з веб-контентом лише через XMLHttpRequest і content scripts. Також extension core не має прямого доступу до хост-машини.

Native Binary

Розширення може мати native binary, який може отримувати доступ до хост-машини з повними привілеями користувача. Native binary взаємодіє з extension core через стандартний Netscape Plugin Application Programming Interface (NPAPI), що використовувався у Flash та інших browser plug-ins.

Boundaries

caution

Щоб отримати повні привілеї користувача, зловмисник має переконати розширення передати шкідливі дані від content script до extension's core і від extension's core до native binary.

Кожен компонент розширення відокремлений один від одного міцними захисними межами. Кожен компонент працює в окремому процесі операційної системи. Content scripts і extension cores запускаються в sandbox processes, недоступних для більшості служб операційної системи.

Крім того, content scripts відокремлені від пов'язаних веб-сторінок шляхом запуску в окремому JavaScript heap. Content script і веб-сторінка мають доступ до того самого underlying DOM, але вони ніколи не обмінюються JavaScript pointers, що запобігає leaking of JavaScript functionality.

manifest.json

A Chrome extension — це просто ZIP-папка з розширенням файлу .crx file extension. Ядром розширення є файл manifest.json у корені папки, який визначає структуру, дозволи та інші параметри конфігурації.

Example:

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

Content scripts завантажуються щоразу, коли користувач переходить на відповідну сторінку — у нашому випадку будь-яка сторінка, що відповідає виразу https://example.com/* і не відповідає регулярному виразу *://*/*/business*. Вони виконуються як власні скрипти сторінки і мають довільний доступ до сторінки через Document Object Model (DOM).

json
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],

Щоб включити або виключити більше URL-адрес, також можна використовувати include_globs та exclude_globs.

Це приклад content script, який додасть кнопку explain на сторінку, коли the storage API використовується для отримання значення 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)
})

Коли ця кнопка натискається, content script відправляє повідомлення на extension pages через використання runtime.sendMessage() API. Це пов'язано з обмеженнями content script щодо прямого доступу до API, серед небагатьох винятків — storage. Для функціональностей поза межами цих винятків повідомлення відправляються на extension pages, з якими content scripts можуть взаємодіяти.

warning

Залежно від браузера можливості content script можуть дещо відрізнятися. Для Chromium-based browsers список можливостей доступний у Chrome Developers documentation, а для Firefox основним джерелом є MDN.
Також варто зауважити, що content scripts можуть спілкуватися з background scripts, що дозволяє їм виконувати дії та передавати відповіді назад.

Для перегляду та відлагодження content scripts у Chrome меню Chrome developer tools можна відкрити через Options > More tools > Developer tools АБО натиснути Ctrl + Shift + I.

Після відкриття developer tools слід перейти на Source tab, а потім — на вкладку Content Scripts. Це дозволяє спостерігати за запущеними content scripts від різних розширень і ставити breakpoints для відстеження потоку виконання.

Інжектовані content scripts

tip

Зверніть увагу, що Content Scripts не є обов'язковими, оскільки також можливо динамічно інжектувати скрипти та програмно впроваджувати їх у веб-сторінки через tabs.executeScript. Це надає більш тонке управління.

Для програмного впровадження content script розширенню необхідно мати host permissions для сторінки, у яку будуть інжектовані скрипти. Ці дозволи можна отримати або шляхом requesting them у manifest розширення, або тимчасово через activeTab.

Приклад розширення, заснованого на activeTab

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.

Content Scripts 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

Повідомлення, надіслані content scripts, отримує background page, яка виконує центральну роль у координації компонентів розширення. Зауважте, що background page зберігається протягом усього життя розширення, працюючи непомітно без прямої взаємодії з користувачем. Вона має власний Document Object Model (DOM), що дозволяє складні взаємодії та управління станом.

Ключові моменти:

  • Background Page Role: Діє як нервовий центр розширення, забезпечуючи комунікацію і координацію між різними частинами розширення.
  • Persistence: Це постійний компонент, невидимий для користувача, але невід'ємний для функціональності розширення.
  • Automatic Generation: Якщо не визначена явно, браузер автоматично створює background page. Автоматично згенерована сторінка включатиме всі background scripts, вказані в manifest розширення, забезпечуючи безперебійну роботу фонових задач розширення.

tip

Зручність, яку надає браузер, автоматично створюючи background page (коли вона не оголошена явно), гарантує, що всі необхідні background scripts інтегровані та працюють, спрощуючи процес налаштування розширення.

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 для прослуховування повідомлень. Коли надходить повідомлення "explain", воно використовує tabs API щоб відкрити сторінку в новій вкладці.

Щоб відлагодити фоновий скрипт, ви можете перейти до extension details and inspect the service worker, це відкриє інструменти розробника з фоновим скриптом:

Options pages and other

Розширення браузера можуть містити різні типи сторінок:

  • Action pages відображаються в drop-down when the extension icon натискається.
  • Сторінки, які розширення буде load in a new tab.
  • Option Pages: Ця сторінка відображається поверх розширення при натисканні. У попередньому manifest у моєму випадку я зміг отримати доступ до цієї сторінки в chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca або натиснувши:

Зверніть увагу, що ці сторінки не є постійними, як background pages, оскільки вони динамічно завантажують вміст у разі потреби. Незважаючи на це, вони мають певні можливості, спільні з фоновою сторінкою:

  • Communication with Content Scripts: Подібно до фонової сторінки, ці сторінки можуть отримувати повідомлення від content scripts, полегшуючи взаємодію всередині розширення.
  • Access to Extension-Specific APIs: Ці сторінки мають повний доступ до extension-specific APIs, залежно від дозволів, визначених для розширення.

permissions & host_permissions

permissions та host_permissions — це записи в manifest.json, які вказують, які дозволи має розширення браузера (storage, location...) і на яких веб-сторінках.

Оскільки розширення браузера можуть мати дуже великі привілеї, шкідливе розширення або компрометоване розширення може надати атакувальнику різні способи крадіжки конфіденційної інформації та стеження за користувачем.

Перевірте, як ці налаштування працюють і як ними можуть зловживати в:

BrowExt - permissions & host_permissions

content_security_policy

A content security policy також може бути оголошена всередині manifest.json. Якщо вона визначена, вона може бути вразливою.

Налаштування за замовчуванням для сторінок розширення браузера досить обмежувальні:

bash
script-src 'self'; object-src 'self';

Для більш детальної інформації про CSP та potential bypasses дивіться:

Content Security Policy (CSP) Bypass

web_accessible_resources

щоб веб-сторінка могла отримати доступ до сторінки Browser Extension, наприклад .html, ця сторінка має бути вказана у полі web_accessible_resources файлу manifest.json.
Наприклад:

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 доступний:

Проте, якщо в manifest.json використовується параметр use_dynamic_url, цей id може бути динамічним.

tip

Зверніть увагу, що навіть якщо сторінка згадується тут, вона може бути захищена від ClickJacking завдяки Content Security Policy. Тож вам також потрібно перевірити її (секція frame-ancestors) перед тим, як підтвердити, що атака ClickJacking можлива.

Дозвіл на доступ до цих сторінок робить їх потенційно вразливими до ClickJacking:

BrowExt - ClickJacking

tip

Дозвіл завантаження цих сторінок лише розширенню, а не довільним URL, може запобігти атакам ClickJacking.

caution

Зауважте, що сторінки з web_accessible_resources та інші сторінки розширення також можуть contacting background scripts. Тому якщо одна з цих сторінок вразлива до XSS, це може відкрити серйознішу вразливість.

Крім того, зауважте, що ви можете відкривати в iframe лише сторінки, вказані в web_accessible_resources, але у новій вкладці можливо отримати доступ до будь-якої сторінки розширення, знаючи extension ID. Отже, якщо XSS знайдено з використанням тих самих параметрів, його можна буде використовувати навіть якщо сторінка не налаштована в web_accessible_resources.

externally_connectable

Згідно з docs, властивість манифеста "externally_connectable" визначає, які розширення та веб-сторінки можуть підключатися до вашого розширення через runtime.connect та runtime.sendMessage.

  • Якщо ключ externally_connectable не оголошено в маніфесті вашого розширення або він оголошений як "ids": ["*"], усі розширення можуть підключатися, але жодні веб-сторінки не можуть.
  • Якщо вказані конкретні IDs, наприклад "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], лише ті додатки можуть підключатися.
  • Якщо вказано matches, ті веб-додатки зможуть підключатися:
json
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
  • Якщо це вказано як пусте: "externally_connectable": {}, жоден app або web не зможе підключитися.

The less extensions and URLs indicated here, the smaller the attack surface will be.

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.

Communication summary

Extension <--> WebApp

To communicate between the content script and the web page post messages are usually used. Therefore, in the web application you will usually find calls to the function window.postMessage and in the content script listeners like window.addEventListener. Note however, that the extension could also communicate with the web application sending a Post Message (and therefore the web should expect it) or just make the web load a new script.

Inside the extension

Usually the function chrome.runtime.sendMessage is used to send a message inside the extension (usually handled by the background script) and in order to receive and handle it a listener is declared calling chrome.runtime.onMessage.addListener.

It's also possible to use chrome.runtime.connect() to have a persistent connection instead of sending single messages, it's possible to use it to send and receive messages like in the following example:

chrome.runtime.connect() приклад
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
})

Також можна надсилати повідомлення з фонового скрипта до скрипта вмісту, розташованого в конкретній вкладці, викликавши chrome.tabs.sendMessage, де потрібно вказати ID вкладки, куди надсилається повідомлення.

Від дозволених externally_connectable до розширення

Веб‑застосунки та зовнішні розширення браузера, дозволені у конфігурації externally_connectable, можуть надсилати запити, використовуючи :

javascript
chrome.runtime.sendMessage(extensionId, ...

Там, де потрібно згадати extension ID.

Native Messaging

Фонові скрипти можуть спілкуватися з бінарними файлами в системі, що може призвести до критичних уразливостей, таких як RCEs, якщо ця комунікація не буде належним чином захищена. More on this later.

javascript
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)

Веб ↔︎ Content Script Комунікація

Середовища, в яких виконуються content scripts, і де існують хост-сторінки, відокремлені одне від одного, забезпечуючи ізоляцію. Незважаючи на цю ізоляцію, обидва можуть взаємодіяти з Document Object Model (DOM) сторінки, спільним ресурсом. Щоб хост-сторінка могла налагодити спілкування з content script, або опосередковано з розширенням через content script, потрібно використовувати DOM, доступний обом сторонам, як канал зв'язку.

Post Messages

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
)
example.js
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: Це True тільки якщо подія була викликана дією користувача
  • The content script might expecting a message only if the user performs some action
  • origin domain: може очікувати повідомлення лише з allowlist доменів.
  • If a regex is used, be very careful
  • Source: received_message.source !== window можна використати, щоб перевірити, чи повідомлення було from the same window де слухає Content Script.

The previous checks, even if performed, could be vulnerable, so check in the following page potential Post Message bypasses:

PostMessage Vulnerabilities

Iframe

Another possible way of communication might be through Iframe URLs, you can find an example in:

BrowExt - XSS Example

DOM

Це не «точно» спосіб комунікації, але веб і content script матимуть доступ до web DOM. Тому, якщо content script читає якусь інформацію з нього, довіряючи web DOM, веб може змінити ці дані (оскільки вебу не слід довіряти, або через вразливість до XSS) і компрометувати Content Script.

You can also find an example of a DOM based XSS to compromise a browser extension in:

BrowExt - XSS Example

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:

javascript
;(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 у вибраній вкладці:

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 обробник подій, щоб обробляти повідомлення. Це виглядає однаково як із контент-скрипта, так і зі сторінки розширення.

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() виконувалася синхронно. Щоб змінити обробник події onMessage для асинхронного виконання sendResponse(), необхідно додати return true;.

Важливо врахувати, що в ситуаціях, коли кілька сторінок налаштовані на отримання подій onMessage, першою сторінкою, що виконає sendResponse() для конкретної події буде єдина, яка зможе ефективно доставити відповідь. Будь-які наступні відповіді на ту саму подію не будуть враховані.

При створенні нових розширень слід надавати перевагу promises замість callbacks. Що стосується використання callbacks, функція sendResponse() вважається дійсною лише якщо вона викликається безпосередньо в синхронному контексті, або якщо обробник події вказує на асинхронну операцію, повертаючи true. Якщо ж жоден з обробників не поверне true або якщо функція sendResponse() буде видалена з пам'яті (garbage-collected), то callback, пов'язаний з функцією sendMessage(), буде викликаний за замовчуванням.

Native Messaging

Розширення браузера також дозволяють спілкуватися з binaries in the system via 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() або runtime.sendNativeMessage() для спілкування з додатком із фонових скриптів розширення браузера. Поле path — шлях до бінарного файлу, є лише 1 дійсний type — stdio (use stdin and stdout), а allowed_origins вказує розширення, які можуть отримати до нього доступ (і не можуть містити wildcard).

Chrome/Chromium шукатиме цей json у реєстрі Windows та в деяких шляхах на macOS і Linux (more info in the docs).

tip

Розширенню браузера також потрібно задекларувати дозвол nativeMessaing, щоб мати змогу використовувати цей канал комунікації.

Ось як виглядає код фонового скрипта, що надсилає повідомлення нативному додатку:

javascript
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)

In this blog post, пропонується вразливий патерн, що зловживає native messages:

  1. Browser extension має wildcard-патерн для content script.
  2. Content script передає повідомлення через postMessage у background script за допомогою sendMessage.
  3. Background script передає повідомлення у native application за допомогою sendNativeMessage.
  4. Native application обробляє повідомлення небезпечно, що призводить до code execution.

І всередині цього наведено приклад як із будь-якої сторінки отримати RCE, зловживаючи browser extension.

Sensitive Information in Memory/Code/Clipboard

Якщо розширення браузера зберігає чутливу інформацію у своїй пам'яті, її можна здампити (особливо на Windows) і відшукати потрібні дані.

Тому пам'ять розширення не слід вважати захищеною, і чутливу інформацію, таку як облікові дані або мнемонічні фрази, не слід зберігати.

Звісно, не зберігайте чутливу інформацію в коді, оскільки код буде публічним.

Щоб здампити пам'ять браузера, можна дампнути процесну пам'ять або у налаштуваннях розширення перейти на Inspect pop-up -> у секції Memory -> Take a snaphost і скористатися CTRL+F, щоб шукати чутливу інформацію в знімку.

Крім того, надзвичайно чутливі дані, як-от мнемонічні ключі чи паролі, не слід дозволяти копіювати у буфер обміну (або принаймні видаляти їх з буфера обміну через кілька секунд), оскільки процеси, що моніторять буфер обміну, зможуть їх отримати.

Loading an Extension in the Browser

  1. Download розширення браузера & розпакуйте
  2. Перейдіть на chrome://extensions/ і увімкніть Developer Mode
  3. Натисніть кнопку Load unpacked

У Firefox перейдіть на about:debugging#/runtime/this-firefox і натисніть кнопку Load Temporary Add-on.

Getting the source code from the store

Вихідний код розширення Chrome можна отримати різними способами. Нижче наведені детальні пояснення та інструкції для кожного варіанту.

Download Extension as ZIP via Command Line

Вихідний код розширення Chrome можна завантажити у вигляді ZIP-файлу за допомогою командного рядка. Це передбачає використання curl для отримання ZIP-файлу за певним URL, а потім розпакування вмісту 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/

Використовуйте розширення CRX Viewer

Інший зручний спосіб — використати Chrome Extension Source Viewer, який є open-source проектом. Його можна встановити з Chrome Web Store. Вихідний код viewer доступний у його GitHub repository.

Перегляд коду локально встановленого розширення

Локально встановлені Chrome розширення також можна інспектувати. Ось як:

  1. Отримайте доступ до локальної папки профілю Chrome, перейшовши на chrome://version/ і знайдіть поле "Profile Path".
  2. Перейдіть у підпапку Extensions/ у каталозі профілю.
  3. Ця папка містить всі встановлені розширення, зазвичай з їхнім вихідним кодом у читаному форматі.

Щоб ідентифікувати розширення, ви можете зіставити їхні ID з назвами:

  • Увімкніть Developer Mode на сторінці about:extensions, щоб побачити ID кожного розширення.
  • У кожній папці розширення файл manifest.json містить читабельне поле name, що допоможе вам ідентифікувати розширення.

Використовуйте File Archiver або Unpacker

Зайдіть у Chrome Web Store і скачаєте розширення. Файл матиме розширення .crx. Змініть розширення файлу з .crx на .zip. Використайте будь-який архіватор (наприклад, WinRAR, 7-Zip тощо), щоб розпакувати вміст ZIP-файлу.

Використовуйте Developer Mode у Chrome

Відкрийте Chrome і перейдіть до chrome://extensions/. Увімкніть "Developer mode" у верхньому правому куті. Натисніть "Load unpacked extension...". Перейдіть до директорії вашого розширення. Це не завантажує вихідний код, але корисно для перегляду та модифікації коду вже завантаженого або розробленого розширення.

Chrome extension manifest dataset

Щоб спробувати знайти вразливі browser extensions, ви можете використати thehttps://github.com/palant/chrome-extension-manifests-dataset і перевірити їхні manifest файли на потенційні ознаки вразливостей. Наприклад, щоб перевірити розширення з більш ніж 25000 users, content_scripts та permission nativeMessaing:

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')"

Post-exploitation: Forced extension load & persistence (Windows)

Stealthy техніка для backdoor-ування Chromium шляхом прямого редагування per-user Preferences і підробки валідних HMACs, що призводить до того, що браузер приймає та активує довільне unpacked extension без підказок або прапорців.

Forced Extension Load Preferences Mac Forgery Windows

Контрольний список аудиту безпеки

Навіть якщо розширення браузера мають обмежену attack surface, деякі з них можуть містити вразливості або можливості для покращення hardening'у. Наведені нижче — найпоширеніші:

  • 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_resources is 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

Ризики розширень браузера

  • The app https://crxaminer.tech/ analyzes some data like the permissions browser extension requests to give a risk level of using the browser extension.

Інструменти

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

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks