# Методологія пентестингу розширень браузера {{#include ../../banners/hacktricks-training.md}} ## Основна інформація Розширення браузера написані на JavaScript і завантажуються браузером у фоновому режимі. Воно має свій [DOM](https://www.w3schools.com/js/js_htmldom.asp), але може взаємодіяти з DOM інших сайтів. Це означає, що воно може скомпрометувати конфіденційність, цілісність і доступність (CIA) інших сайтів. ## Основні компоненти Макети розширень виглядають найкраще, коли їх візуалізують, і складаються з трьох компонентів. Розглянемо кожен компонент детальніше.

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

### **Скрипти контенту** Кожен скрипт контенту має прямий доступ до DOM **однієї веб-сторінки** і, таким чином, піддається **потенційно шкідливому вводу**. Однак скрипт контенту не має жодних дозволів, окрім можливості надсилати повідомлення до ядра розширення. ### **Ядро розширення** Ядро розширення містить більшість привілеїв/доступу розширення, але ядро розширення може взаємодіяти з веб-контентом лише через [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) та скрипти контенту. Крім того, ядро розширення не має прямого доступу до хост-машини. ### **Рідний бінарний файл** Розширення дозволяє рідний бінарний файл, який може **доступатися до хост-машини з повними привілеями користувача.** Рідний бінарний файл взаємодіє з ядром розширення через стандартний Інтерфейс програмування додатків плагінів Netscape ([NPAPI](https://en.wikipedia.org/wiki/NPAPI)), який використовується Flash та іншими плагінами браузера. ### Межі > [!CAUTION] > Щоб отримати повні привілеї користувача, зловмисник повинен переконати розширення передати шкідливий ввід від скрипта контенту до ядра розширення і від ядра розширення до рідного бінарного файлу. Кожен компонент розширення відокремлений один від одного **сильними захисними межами**. Кожен компонент працює в **окремому процесі операційної системи**. Скрипти контенту та ядра розширення працюють у **пісочницях**, недоступних для більшості служб операційної системи. Більше того, скрипти контенту відокремлені від своїх асоційованих веб-сторінок, **працюючи в окремій купі JavaScript**. Скрипт контенту та веб-сторінка мають **доступ до одного й того ж базового DOM**, але двоє **ніколи не обмінюються вказівниками JavaScript**, що запобігає витоку функціональності JavaScript. ## **`manifest.json`** Розширення Chrome - це просто ZIP-папка з [.crx file extension](https://www.lifewire.com/crx-file-2620391). Ядро розширення - це **`manifest.json`** файл у корені папки, який вказує макет, дозволи та інші параметри конфігурації. Приклад: ```json { "manifest_version": 2, "name": "My extension", "version": "1.0", "permissions": ["storage"], "content_scripts": [ { "js": ["script.js"], "matches": ["https://example.com/*", "https://www.example.com/*"], "exclude_matches": ["*://*/*business*"] } ], "background": { "scripts": ["background.js"] }, "options_ui": { "page": "options.html" } } ``` ### `content_scripts` Скрипти контенту **завантажуються** щоразу, коли користувач **переміщується на відповідну сторінку**, у нашому випадку на будь-яку сторінку, що відповідає виразу **`https://example.com/*`** і не відповідає регулярному виразу **`*://*/*/business*`**. Вони виконуються **як власні скрипти сторінки** і мають довільний доступ до [Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) сторінки. ```json "content_scripts": [ { "js": [ "script.js" ], "matches": [ "https://example.com/*", "https://www.example.com/*" ], "exclude_matches": ["*://*/*business*"], } ], ``` Щоб включити або виключити більше URL-адрес, також можна використовувати **`include_globs`** та **`exclude_globs`**. Це приклад контентного скрипта, який додасть кнопку пояснення на сторінку, коли [API зберігання](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage) буде використовуватися для отримання значення `message` з пам'яті розширення. ```js chrome.storage.local.get("message", (result) => { let div = document.createElement("div") div.innerHTML = result.message + " " div.querySelector("button").addEventListener("click", () => { chrome.runtime.sendMessage("explain") }) document.body.appendChild(div) }) ```
Повідомлення надсилається на сторінки розширення скриптом контенту, коли натискається ця кнопка, за допомогою [**runtime.sendMessage() API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage). Це пов'язано з обмеженням скрипта контенту в прямому доступі до API, з `storage`, що є одним з небагатьох винятків. Для функціональностей, що виходять за межі цих винятків, повідомлення надсилаються на сторінки розширення, з якими можуть спілкуватися скрипти контенту. > [!WARNING] > Залежно від браузера, можливості скрипта контенту можуть трохи відрізнятися. Для браузерів на базі Chromium список можливостей доступний у [документації Chrome Developers](https://developer.chrome.com/docs/extensions/mv3/content_scripts/#capabilities), а для Firefox [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis) слугує основним джерелом.\ > Також варто зазначити, що скрипти контенту мають можливість спілкуватися зі скриптами фону, що дозволяє їм виконувати дії та передавати відповіді назад. Для перегляду та налагодження скриптів контенту в Chrome меню інструментів розробника можна отримати з Options > More tools > Developer tools АБО натиснувши Ctrl + Shift + I. Після відображення інструментів розробника потрібно натиснути на **Source tab**, а потім на **Content Scripts** tab. Це дозволяє спостерігати за запущеними скриптами контенту з різних розширень та встановлювати точки зупинки для відстеження потоку виконання. ### Впроваджені скрипти контенту > [!TIP] > Зверніть увагу, що **скрипти контенту не є обов'язковими**, оскільки також можливо **динамічно** **впроваджувати** скрипти та **програмно впроваджувати їх** на веб-сторінках за допомогою **`tabs.executeScript`**. Це насправді забезпечує більше **докладних контролів**. Для програмного впровадження скрипта контенту розширення повинно мати [дозволи хоста](https://developer.chrome.com/docs/extensions/reference/permissions) для сторінки, на яку потрібно впровадити скрипти. Ці дозволи можуть бути отримані або **запитуючи їх** у маніфесті розширення, або на тимчасовій основі через [**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab). #### Приклад розширення на основі activeTab ```json:manifest.json { "name": "My extension", ... "permissions": [ "activeTab", "scripting" ], "background": { "service_worker": "background.js" }, "action": { "default_title": "Action Button" } } ``` - **Вставити JS файл при натисканні:** ```javascript // content-script.js document.body.style.backgroundColor = "orange" //service-worker.js - Inject the JS file chrome.action.onClicked.addListener((tab) => { chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ["content-script.js"], }) }) ``` - **Впровадити функцію** при натисканні: ```javascript //service-worker.js - Inject a function function injectedFunction() { document.body.style.backgroundColor = "orange" } chrome.action.onClicked.addListener((tab) => { chrome.scripting.executeScript({ target: { tabId: tab.id }, func: injectedFunction, }) }) ``` #### Приклад з дозволами на скрипти ```javascript // service-workser.js chrome.scripting.registerContentScripts([ { id: "test", matches: ["https://*.example.com/*"], excludeMatches: ["*://*/*business*"], js: ["contentScript.js"], }, ]) // Another example chrome.tabs.executeScript(tabId, { file: "content_script.js" }) ``` Щоб включити або виключити більше URL-адрес, також можна використовувати **`include_globs`** та **`exclude_globs`**. ### Content Scripts `run_at` Поле `run_at` контролює **коли JavaScript файли впроваджуються на веб-сторінку**. Бажане та значення за замовчуванням - це `"document_idle"`. Можливі значення: - **`document_idle`**: Коли це можливо - **`document_start`**: Після будь-яких файлів з `css`, але до того, як буде побудовано будь-який інший DOM або виконано будь-який інший скрипт. - **`document_end`**: Негайно після завершення DOM, але до того, як підресурси, такі як зображення та фрейми, завантажилися. #### Via `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` Повідомлення, надіслані скриптами контенту, отримуються **фоновою сторінкою**, яка відіграє центральну роль у координації компонентів розширення. Зокрема, фонова сторінка зберігається протягом усього життя розширення, працюючи непомітно без прямої взаємодії з користувачем. Вона має власну модель об'єктів документа (DOM), що дозволяє здійснювати складні взаємодії та управління станом. **Ключові моменти**: - **Роль фонової сторінки:** Виконує функцію нервового центру для розширення, забезпечуючи зв'язок і координацію між різними частинами розширення. - **Постійність:** Це завжди присутня сутність, невидима для користувача, але важлива для функціональності розширення. - **Автоматичне створення:** Якщо не визначено явно, браузер автоматично створить фонову сторінку. Ця автоматично згенерована сторінка міститиме всі фонові скрипти, зазначені в маніфесті розширення, забезпечуючи безперебійну роботу фонових завдань розширення. > [!TIP] > Зручність, яку надає браузер, автоматично створюючи фонову сторінку (коли вона не оголошена явно), забезпечує інтеграцію та функціонування всіх необхідних фонових скриптів, спрощуючи процес налаштування розширення. Приклад фонового скрипту: ```js chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request == "explain") { chrome.tabs.create({ url: "https://example.net/explanation" }) } }) ``` Він використовує [runtime.onMessage API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) для прослуховування повідомлень. Коли отримується повідомлення `"explain"`, він використовує [tabs API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) для відкриття сторінки в новій вкладці. Щоб налагодити фоновий скрипт, ви можете перейти до **деталей розширення та перевірити сервісний працівник,** це відкриє інструменти розробника з фоновим скриптом:
### Сторінки параметрів та інше Розширення браузера можуть містити різні види сторінок: - **Сторінки дій** відображаються в **випадному меню, коли натискається іконка розширення.** - Сторінки, які розширення буде **завантажувати в новій вкладці.** - **Сторінки параметрів**: Ця сторінка відображається поверх розширення при натисканні. У попередньому маніфесті в моєму випадку я зміг отримати доступ до цієї сторінки за адресою `chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` або натиснувши:
Зверніть увагу, що ці сторінки не є постійними, як фонові сторінки, оскільки вони динамічно завантажують вміст за необхідності. Незважаючи на це, вони мають певні можливості з фоновою сторінкою: - **Зв'язок з контентними скриптами:** Подібно до фонової сторінки, ці сторінки можуть отримувати повідомлення від контентних скриптів, що полегшує взаємодію в межах розширення. - **Доступ до специфічних API розширення:** Ці сторінки мають повний доступ до специфічних API розширення, залежно від дозволів, визначених для розширення. ### `permissions` & `host_permissions` **`permissions`** та **`host_permissions`** є записами з `manifest.json`, які вказують **які дозволи** має розширення браузера (сховище, місцезнаходження...) і на **яких веб-сторінках**. Оскільки розширення браузера можуть бути настільки **привілейованими**, зловмисне або скомпрометоване може дозволити зловмиснику **різні способи викрадення чутливої інформації та шпигунства за користувачем**. Перевірте, як ці налаштування працюють і як їх можна зловживати в: {{#ref}} browext-permissions-and-host_permissions.md {{#endref}} ### `content_security_policy` **Політику безпеки вмісту** також можна оголосити всередині `manifest.json`. Якщо вона визначена, вона може бути **вразливою**. За замовчуванням налаштування для сторінок розширення браузера є досить обмежувальними: ```bash script-src 'self'; object-src 'self'; ``` Для отримання додаткової інформації про CSP та потенційні обходи, перегляньте: {{#ref}} ../content-security-policy-csp-bypass/ {{#endref}} ### `web_accessible_resources` щоб веб-сторінка могла отримати доступ до сторінки розширення браузера, наприклад, `.html` сторінки, ця сторінка повинна бути зазначена в полі **`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:///message.html ``` У публічних розширеннях **extension-id доступний**:
Однак, якщо параметр `manifest.json` **`use_dynamic_url`** використовується, цей **id може бути динамічним**. > [!TIP] > Зверніть увагу, що навіть якщо сторінка згадується тут, вона може бути **захищена від ClickJacking** завдяки **Content Security Policy**. Тому вам також потрібно перевірити це (розділ frame-ancestors) перед підтвердженням можливості атаки ClickJacking. Доступ до цих сторінок робить їх **потенційно вразливими до ClickJacking**: {{#ref}} browext-clickjacking.md {{#endref}} > [!TIP] > Дозволяючи завантажувати ці сторінки лише через розширення, а не через випадкові URL, можна запобігти атакам ClickJacking. > [!CAUTION] > Зверніть увагу, що сторінки з **`web_accessible_resources`** та інші сторінки розширення також можуть **контактувати з фоновими скриптами**. Тому, якщо одна з цих сторінок вразлива до **XSS**, це може відкрити більшу вразливість. > > Більше того, зверніть увагу, що ви можете відкривати лише сторінки, вказані в **`web_accessible_resources`** всередині iframe, але з нової вкладки можливо отримати доступ до будь-якої сторінки в розширенні, знаючи ID розширення. Тому, якщо XSS виявлено, зловживаючи тими ж параметрами, це може бути використано, навіть якщо сторінка не налаштована в **`web_accessible_resources`**. ### `externally_connectable` Згідно з [**документацією**](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable), властивість маніфесту `"externally_connectable"` оголошує **які розширення та веб-сторінки можуть підключатися** до вашого розширення через [runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect) та [runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage). - Якщо ключ **`externally_connectable`** **не** оголошений у маніфесті вашого розширення або він оголошений як **`"ids": ["*"]`**, **всі розширення можуть підключатися, але жодні веб-сторінки не можуть підключатися**. - Якщо **вказані конкретні ID**, як у `"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`, **тільки ці програми** можуть підключатися. - Якщо **вказані збіги**, ці веб-додатки зможуть підключатися: ```json "matches": [ "https://*.google.com/*", "*://*.chromium.org/*", ``` - Якщо вказано як порожнє: **`"externally_connectable": {}`**, жоден додаток або веб-сайт не зможе підключитися. Чим **менше розширень і URL-адрес** вказано тут, тим **менша площа атаки** буде. > [!CAUTION] > Якщо веб-сторінка **вразлива до XSS або захоплення** вказана в **`externally_connectable`**, зловмисник зможе **надсилати повідомлення безпосередньо до фонового скрипта**, повністю обходячи Контентний скрипт і його CSP. > > Тому це є **дуже потужним обходом**. > > Більше того, якщо клієнт встановить шкідливе розширення, навіть якщо йому не дозволено спілкуватися з вразливим розширенням, воно може впроваджувати **XSS дані на дозволеній веб-сторінці** або зловживати **`WebRequest`** або **`DeclarativeNetRequest`** API для маніпуляції запитами на цільовому домені, змінюючи запит сторінки на **файл JavaScript**. (Зверніть увагу, що CSP на цільовій сторінці може запобігти цим атакам). Ця ідея походить [**з цього опису**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability). ## Підсумок комунікації ### Розширення <--> Веб-додаток Для комунікації між контентним скриптом і веб-сторінкою зазвичай використовуються повідомлення. Тому в веб-додатку ви зазвичай знайдете виклики функції **`window.postMessage`** і в контентному скрипті слухачі, такі як **`window.addEventListener`**. Зверніть увагу, що розширення також може **спілкуватися з веб-додатком, надсилаючи Post Message** (і тому веб повинен це очікувати) або просто змусити веб завантажити новий скрипт. ### Всередині розширення Зазвичай функція **`chrome.runtime.sendMessage`** використовується для надсилання повідомлення всередині розширення (зазвичай обробляється `background` скриптом), а для отримання та обробки його оголошується слухач, який викликає **`chrome.runtime.onMessage.addListener`**. Також можливо використовувати **`chrome.runtime.connect()`** для встановлення постійного з'єднання замість надсилання окремих повідомлень, його можна використовувати для **надсилання** та **отримання** **повідомлень**, як у наступному прикладі:
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, ... ``` Де потрібно згадати **ідентифікатор розширення**. ### Native Messaging Можливо, що фонові скрипти спілкуються з двійковими файлами в системі, які можуть бути **схильні до критичних вразливостей, таких як RCE** якщо це спілкування не буде належним чином захищене. [Більше про це пізніше](./#native-messaging). ```javascript chrome.runtime.sendNativeMessage( "com.my_company.my_application", { text: "Hello" }, function (response) { console.log("Received " + response) } ) ``` ## Веб **↔︎** Комунікація скриптів контенту Середовища, в яких працюють **скрипти контенту**, і де існують хост-сторінки, **відокремлені** одне від одного, що забезпечує **ізоляцію**. Незважаючи на цю ізоляцію, обидві сторони мають можливість взаємодіяти з **Моделлю об'єктів документа (DOM)** сторінки, спільним ресурсом. Щоб хост-сторінка могла взаємодіяти з **скриптом контенту** або непрямо з розширенням через скрипт контенту, необхідно використовувати **DOM**, доступний обом сторонам, як канал комунікації. ### Повідомлення ```javascript:content-script.js // This is like "chrome.runtime.sendMessage" but to maintain the connection var port = chrome.runtime.connect() window.addEventListener( "message", (event) => { // We only accept messages from ourselves if (event.source !== window) { return } if (event.data.type && event.data.type === "FROM_PAGE") { console.log("Content script received: " + event.data.text) // Forward the message to the background script port.postMessage(event.data.text) } }, false ) ``` ```javascript:example.js document.getElementById("theButton").addEventListener( "click", () => { window.postMessage( { type: "FROM_PAGE", text: "Hello from the webpage!" }, "*" ) }, false ) ``` Безпечна комунікація Post Message повинна перевіряти автентичність отриманого повідомлення, це можна зробити, перевіряючи: - **`event.isTrusted`**: Це True тільки якщо подія була викликана дією користувача - Контент-скрипт може очікувати повідомлення тільки якщо користувач виконує якусь дію - **origin domain**: може очікувати повідомлення тільки з дозволеного списку доменів. - Якщо використовується regex, будьте дуже обережні - **Source**: `received_message.source !== window` може бути використано для перевірки, чи повідомлення було **з того ж вікна**, де слухає Контент-скрипт. Попередні перевірки, навіть якщо вони виконані, можуть бути вразливими, тому перевірте на наступній сторінці **потенційні обходи Post Message**: {{#ref}} ../postmessage-vulnerabilities/ {{#endref}} ### Iframe Ще один можливий спосіб комунікації може бути через **Iframe URLs**, ви можете знайти приклад у: {{#ref}} browext-xss-example.md {{#endref}} ### DOM Це не "точно" спосіб комунікації, але **веб і контент-скрипт матимуть доступ до веб DOM**. Тому, якщо **контент-скрипт** читає якусь інформацію з нього, **довіряючи веб DOM**, веб може **модифікувати ці дані** (тому що веб не повинен бути довіреним, або тому що веб вразливий до XSS) і **скомпрометувати Контент-скрипт**. Ви також можете знайти приклад **DOM на основі XSS для компрометації розширення браузера** у: {{#ref}} browext-xss-example.md {{#endref}} ## Комунікація Контент-скрипта **↔︎** Фоновий скрипт Контент-скрипт може використовувати функції [**runtime.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage) **або** [**tabs.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/tabs#method-sendMessage) для відправки **одноразового JSON-серіалізованого** повідомлення. Щоб обробити **відповідь**, використовуйте повернутий **Promise**. Хоча, для зворотної сумісності, ви все ще можете передати **callback** як останній аргумент. Відправка запиту з **контент-скрипта** виглядає так: ```javascript ;(async () => { const response = await chrome.runtime.sendMessage({ greeting: "hello" }) // do something with response here, not outside the function console.log(response) })() ``` Відправка запиту з **розширення** (зазвичай **фоновий скрипт**). Приклад того, як надіслати повідомлення до контент-скрипту у вибраній вкладці: ```javascript // From https://stackoverflow.com/questions/36153999/how-to-send-a-message-between-chrome-extension-popup-and-content-script ;(async () => { const [tab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true, }) const response = await chrome.tabs.sendMessage(tab.id, { greeting: "hello" }) // do something with response here, not outside the function console.log(response) })() ``` На **приймальному боці** вам потрібно налаштувати [**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **слухача подій**, щоб обробити повідомлення. Це виглядає однаково з контентного скрипта або сторінки розширення. ```javascript // From https://stackoverflow.com/questions/70406787/javascript-send-message-from-content-js-to-background-js chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { console.log( sender.tab ? "from a content script:" + sender.tab.url : "from the extension" ) if (request.greeting === "hello") sendResponse({ farewell: "goodbye" }) }) ``` У наведеному прикладі **`sendResponse()`** було виконано синхронно. Щоб змінити обробник події `onMessage` для асинхронного виконання `sendResponse()`, необхідно додати `return true;`. Важливим моментом є те, що в ситуаціях, коли кілька сторінок налаштовані на отримання подій `onMessage`, **перша сторінка, яка виконає `sendResponse()`** для конкретної події, буде єдиною, яка зможе ефективно доставити відповідь. Будь-які подальші відповіді на ту ж подію не будуть враховані. При створенні нових розширень перевага повинна надаватися промісам, а не зворотним викликам. Що стосується використання зворотних викликів, функція `sendResponse()` вважається дійсною лише в тому випадку, якщо вона виконується безпосередньо в синхронному контексті або якщо обробник події вказує на асинхронну операцію, повертаючи `true`. Якщо жоден з обробників не повертає `true` або якщо функція `sendResponse()` видаляється з пам'яті (збирається сміття), зворотний виклик, пов'язаний з функцією `sendMessage()`, буде викликаний за замовчуванням. ## Native Messaging Розширення браузера також дозволяють спілкуватися з **бінарними файлами в системі через stdin**. Додаток повинен встановити json, що вказує на це, у json, як: ```json { "name": "com.my_company.my_application", "description": "My Application", "path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe", "type": "stdio", "allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"] } ``` Де `name` - це рядок, переданий до [`runtime.connectNative()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-connectNative) або [`runtime.sendNativeMessage()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-sendNativeMessage) для зв'язку з додатком з фонових скриптів розширення браузера. `path` - це шлях до бінарного файлу, є лише 1 дійсний `type`, який є stdio (використовуйте stdin і stdout), а `allowed_origins` вказує на розширення, які можуть отримати доступ до нього (і не можуть мати символи підстановки). Chrome/Chromium буде шукати цей json у деяких реєстрах Windows та деяких шляхах у macOS і Linux (більше інформації в [**docs**](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging)). > [!TIP] > Розширення браузера також потребує дозволу `nativeMessaing`, щоб мати можливість використовувати це спілкування. Ось як виглядає код деякого фонового скрипта, що надсилає повідомлення до рідного додатку: ```javascript chrome.runtime.sendNativeMessage( "com.my_company.my_application", { text: "Hello" }, function (response) { console.log("Received " + response) } ) ``` У [**цьому блозі**](https://spaceraccoon.dev/universal-code-execution-browser-extensions/) пропонується вразливий шаблон, що зловживає нативними повідомленнями: 1. Розширення браузера має шаблон з підстановкою для контентного скрипта. 2. Контентний скрипт передає повідомлення `postMessage` до фонової скрипта, використовуючи `sendMessage`. 3. Фоновий скрипт передає повідомлення до нативного додатку, використовуючи `sendNativeMessage`. 4. Нативний додаток обробляє повідомлення небезпечно, що призводить до виконання коду. І всередині нього пояснюється приклад **переміщення з будь-якої сторінки до RCE, зловживаючи розширенням браузера**. ## Чутлива інформація в пам'яті/коді/буфері обміну Якщо Розширення Браузера зберігає **чутливу інформацію в своїй пам'яті**, її можна **вивантажити** (особливо на машинах з Windows) і **пошукати** цю інформацію. Отже, пам'ять Розширення Браузера **не повинна вважатися безпечною**, і **чутливу інформацію**, таку як облікові дані або мнемонічні фрази, **не слід зберігати**. Звичайно, **не слід вставляти чутливу інформацію в код**, оскільки вона буде **публічною**. Щоб вивантажити пам'ять з браузера, ви можете **вивантажити пам'ять процесу** або перейти до **налаштувань** розширення браузера, натиснувши **`Перевірити спливаюче вікно`** -> У розділі **`Пам'ять`** -> **`Зробити знімок`** і **`CTRL+F`** для пошуку чутливої інформації в знімку. Більш того, надзвичайно чутливу інформацію, таку як мнемонічні ключі або паролі, **не слід дозволяти копіювати в буфер обміну** (або принаймні видалити її з буфера обміну через кілька секунд), оскільки тоді процеси, що моніторять буфер обміну, зможуть їх отримати. ## Завантаження розширення в браузері 1. **Завантажте** Розширення Браузера та розпакуйте його. 2. Перейдіть до **`chrome://extensions/`** і **увімкніть** `Режим розробника`. 3. Натисніть кнопку **`Завантажити розпаковане`**. У **Firefox** перейдіть до **`about:debugging#/runtime/this-firefox`** і натисніть кнопку **`Завантажити тимчасове доповнення`**. ## Отримання вихідного коду з магазину Вихідний код розширення Chrome можна отримати різними способами. Нижче наведені детальні пояснення та інструкції для кожного варіанту. ### Завантаження розширення як ZIP через командний рядок Вихідний код розширення 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/](https://robwu.nl/crxviewer/) ### Використовуйте розширення CRX Viewer Ще один зручний метод - це використання Chrome Extension Source Viewer, який є проектом з відкритим вихідним кодом. Його можна встановити з [Chrome Web Store](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=en). Вихідний код переглядача доступний у його [GitHub репозиторії](https://github.com/Rob--W/crxviewer). ### Перегляд виходу локально встановленого розширення Розширення Chrome, встановлені локально, також можна перевірити. Ось як: 1. Доступ до вашого локального профілю Chrome, відвідавши `chrome://version/` і знайдіть поле "Profile Path". 2. Перейдіть до підпапки `Extensions/` у каталозі профілю. 3. Ця папка містить всі встановлені розширення, зазвичай з їх вихідним кодом у читабельному форматі. Щоб ідентифікувати розширення, ви можете зіставити їх ID з іменами: - Увімкніть режим розробника на сторінці `about:extensions`, щоб побачити ID кожного розширення. - У кожній папці розширення файл `manifest.json` містить читабельне поле `name`, що допомагає вам ідентифікувати розширення. ### Використовуйте архіватор або розпаковувач файлів Перейдіть до Chrome Web Store і завантажте розширення. Файл матиме розширення `.crx`. Змініть розширення файлу з `.crx` на `.zip`. Використовуйте будь-який архіватор (такий як WinRAR, 7-Zip тощо), щоб витягти вміст ZIP-файлу. ### Використовуйте режим розробника в Chrome Відкрийте Chrome і перейдіть до `chrome://extensions/`. Увімкніть "Режим розробника" у верхньому правому куті. Натисніть "Завантажити розпаковане розширення...". Перейдіть до каталогу вашого розширення. Це не завантажує вихідний код, але корисно для перегляду та модифікації коду вже завантаженого або розробленого розширення. ## Набір даних маніфестів розширень Chrome Щоб спробувати виявити вразливі браузерні розширення, ви можете використовувати [https://github.com/palant/chrome-extension-manifests-dataset](https://github.com/palant/chrome-extension-manifests-dataset) і перевірити їх маніфест-файли на наявність потенційно вразливих ознак. Наприклад, щоб перевірити розширення з більш ніж 25000 користувачів, `content_scripts` та дозволом `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')" ``` ## Перевірочний список безпеки Навіть якщо розширення браузера має **обмежену поверхню атаки**, деякі з них можуть містити **вразливості** або **потенційні поліпшення безпеки**. Найбільш поширені з них: - [ ] **Обмежити** запитувані **`permissions`** якомога більше - [ ] **Обмежити** **`host_permissions`** якомога більше - [ ] Використовувати **сильну** **`content_security_policy`** - [ ] **Обмежити** **`externally_connectable`** якомога більше, якщо це не потрібно і можливо, не залишайте його за замовчуванням, вкажіть **`{}`** - [ ] Якщо тут згадується **URL, вразливий до XSS або захоплення**, зловмисник зможе **надсилати повідомлення безпосередньо до фонових скриптів**. Дуже потужний обхід. - [ ] **Обмежити** **`web_accessible_resources`** якомога більше, навіть порожні, якщо можливо. - [ ] Якщо **`web_accessible_resources`** не порожні, перевірте на [**ClickJacking**](browext-clickjacking.md) - [ ] Якщо відбувається будь-яка **комунікація** від **розширення** до **веб-сторінки**, [**перевірте на XSS**](browext-xss-example.md) **вразливості**, викликані в комунікації. - [ ] Якщо використовуються повідомлення Post, перевірте на [**вразливості Post Message**](../postmessage-vulnerabilities/)**.** - [ ] Якщо **Content Script отримує доступ до деталей DOM**, перевірте, що вони **не вводять XSS**, якщо їх **модифікують** веб - [ ] Зробіть особливий акцент, якщо ця комунікація також залучена в **комунікацію Content Script -> Фоновий скрипт** - [ ] Якщо фоновий скрипт спілкується через **native messaging**, перевірте, що комунікація є безпечною та очищеною - [ ] **Чутливу інформацію не слід зберігати** всередині коду розширення браузера - [ ] **Чутливу інформацію не слід зберігати** всередині пам'яті розширення браузера - [ ] **Чутливу інформацію не слід зберігати** всередині **файлової системи без захисту** ## Ризики розширення браузера - Додаток [https://crxaminer.tech/](https://crxaminer.tech/) аналізує деякі дані, такі як дозволи, які запитує розширення браузера, щоб надати рівень ризику використання розширення браузера. ## Інструменти ### [**Tarnish**](https://thehackerblog.com/tarnish/) - Завантажує будь-яке розширення Chrome з наданого посилання на веб-магазин Chrome. - [**manifest.json**](https://developer.chrome.com/extensions/manifest) **переглядач**: просто відображає версію JSON з форматуванням розширення. - **Аналіз відбитків**: Виявлення [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) та автоматичне генерування JavaScript для відбитків розширення Chrome. - **Аналіз потенційного Clickjacking**: Виявлення HTML-сторінок розширення з встановленою директивою [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources). Вони можуть бути вразливими до clickjacking в залежності від мети сторінок. - **Переглядач попереджень про дозволи**: який показує список усіх попереджень про запити дозволів Chrome, які будуть відображені при спробі користувача встановити розширення. - **Небезпечні функції**: показує місце розташування небезпечних функцій, які можуть бути потенційно використані зловмисником (наприклад, функції, такі як innerHTML, chrome.tabs.executeScript). - **Точки входу**: показує, де розширення приймає вхідні дані від користувача/зовнішніх джерел. Це корисно для розуміння поверхні розширення та пошуку потенційних точок для надсилання зловмисно створених даних до розширення. - Як сканери Небезпечних функцій, так і Точок входу мають наступне для своїх згенерованих сповіщень: - Відповідний фрагмент коду та рядок, що викликав сповіщення. - Опис проблеми. - Кнопка "Переглянути файл", щоб переглянути повний вихідний файл, що містить код. - Шлях до сповіщеного файлу. - Повний URI розширення Chrome сповіщеного файлу. - Тип файлу, наприклад, скрипт фонової сторінки, скрипт контенту, дія браузера тощо. - Якщо вразливий рядок знаходиться в JavaScript-файлі, шляхи всіх сторінок, де він включений, а також тип цих сторінок і статус [web_accessible_resource](https://developer.chrome.com/extensions/manifest/web_accessible_resources). - **Аналізатор політики безпеки контенту (CSP) та перевірка обходу**: Це вказує на слабкі місця в CSP вашого розширення та також виявляє будь-які потенційні способи обійти ваш CSP через білих CDN тощо. - **Відомі вразливі бібліотеки**: Це використовує [Retire.js](https://retirejs.github.io/retire.js/) для перевірки наявності використання відомих вразливих JavaScript-бібліотек. - Завантажити розширення та відформатовані версії. - Завантажити оригінальне розширення. - Завантажити покращену версію розширення (автоформатований HTML та JavaScript). - Автоматичне кешування результатів сканування, запуск сканування розширення займе багато часу під час першого запуску. Однак під час другого запуску, якщо розширення не було оновлено, це буде майже миттєво через кешування результатів. - Посилання на звіти, які легко посилати іншим на звіт про розширення, згенерований tarnish. ### [Neto](https://github.com/elevenpaths/neto) Проект Neto - це пакет Python 3, призначений для аналізу та виявлення прихованих функцій плагінів і розширень браузера для відомих браузерів, таких як Firefox і Chrome. Він автоматизує процес розпакування упакованих файлів для вилучення цих функцій з відповідних ресурсів у розширенні, таких як `manifest.json`, папки локалізації або вихідні файли JavaScript і HTML. ## Посилання - **Дякуємо** [**@naivenom**](https://twitter.com/naivenom) **за допомогу з цією методологією** - [https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing](https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing) - [https://palant.info/2022/08/10/anatomy-of-a-basic-extension/](https://palant.info/2022/08/10/anatomy-of-a-basic-extension/) - [https://palant.info/2022/08/24/attack-surface-of-extension-pages/](https://palant.info/2022/08/24/attack-surface-of-extension-pages/) - [https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/) - [https://help.passbolt.com/assets/files/PBL-02-report.pdf](https://help.passbolt.com/assets/files/PBL-02-report.pdf) - [https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts) - [https://developer.chrome.com/docs/extensions/mv2/background-pages](https://developer.chrome.com/docs/extensions/mv2/background-pages) - [https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/](https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/) - [https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0](https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0) {{#include ../../banners/hacktricks-training.md}}