Методологія 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
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Базова інформація
Browser extensions написані на JavaScript і завантажуються браузером у фоновому режимі. Вони мають свій DOM, але можуть взаємодіяти з DOM інших сайтів. Це означає, що вони можуть ставити під загрозу конфіденційність, цілісність і доступність (CIA) інших сайтів.
Основні компоненти
Структура розширення легше сприймається при візуалізації і складається з трьох компонентів. Розглянемо кожен компонент докладніше.
 (1) (1).png)
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:
{
"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).
"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
зі сховища розширення.
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)
Коли ця кнопка натискається, 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
{
"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"],
})
})
- Впровадити функцію при натисканні:
//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
.
Content Scripts 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
Повідомлення, надіслані 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:
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
або натиснувши:
.png)
Зверніть увагу, що ці сторінки не є постійними, як 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
. Якщо вона визначена, вона може бути вразливою.
Налаштування за замовчуванням для сторінок розширення браузера досить обмежувальні:
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
.
Наприклад:
{
...
"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
Зверніть увагу, що навіть якщо сторінка згадується тут, вона може бути захищена від ClickJacking завдяки Content Security Policy. Тож вам також потрібно перевірити її (секція frame-ancestors) перед тим, як підтвердити, що атака ClickJacking можлива.
Дозвіл на доступ до цих сторінок робить їх потенційно вразливими до 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, ті веб-додатки зможуть підключатися:
"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()
приклад
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
, можуть надсилати запити, використовуючи :
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)
}
)
Веб ↔︎ Content Script Комунікація
Середовища, в яких виконуються 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
: Це 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:
Iframe
Another possible way of communication might be through Iframe URLs, you can find an example in:
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:
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 обробник подій, щоб обробляти повідомлення. Це виглядає однаково як із контент-скрипта, так і зі сторінки розширення.
// 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 такого вигляду:
{
"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
, щоб мати змогу використовувати цей канал комунікації.
Ось як виглядає код фонового скрипта, що надсилає повідомлення нативному додатку:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In this blog post, пропонується вразливий патерн, що зловживає native messages:
- Browser extension має wildcard-патерн для content script.
- Content script передає повідомлення через
postMessage
у background script за допомогоюsendMessage
. - Background script передає повідомлення у native application за допомогою
sendNativeMessage
. - 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
- Download розширення браузера & розпакуйте
- Перейдіть на
chrome://extensions/
і увімкнітьDeveloper Mode
- Натисніть кнопку
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 у директорію. Ось кроки:
- Замініть
"extension_id"
на фактичний ID розширення. - Виконайте наступні команди:
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
Інший зручний спосіб — використати Chrome Extension Source Viewer, який є open-source проектом. Його можна встановити з Chrome Web Store. Вихідний код viewer доступний у його GitHub repository.
Перегляд коду локально встановленого розширення
Локально встановлені Chrome розширення також можна інспектувати. Ось як:
- Отримайте доступ до локальної папки профілю Chrome, перейшовши на
chrome://version/
і знайдіть поле "Profile Path". - Перейдіть у підпапку
Extensions/
у каталозі профілю. - Ця папка містить всі встановлені розширення, зазвичай з їхнім вихідним кодом у читаному форматі.
Щоб ідентифікувати розширення, ви можете зіставити їхні 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
:
# 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
- Дякуємо @naivenom за допомогу з цією методологією
- 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 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
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.