.. | ||
browext-clickjacking.md | ||
browext-permissions-and-host_permissions.md | ||
browext-xss-example.md | ||
README.md |
Методологія пентестингу браузерних розширень
{% hint style="success" %}
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи Telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на GitHub.
Основна інформація
Браузерні розширення написані на JavaScript і завантажуються браузером у фоновому режимі. Вони мають свій DOM, але можуть взаємодіяти з DOM інших сайтів. Це означає, що вони можуть скомпрометувати конфіденційність, цілісність і доступність (CIA) інших сайтів.
Основні компоненти
Макети розширень виглядають найкраще, коли їх візуалізують, і складаються з трьох компонентів. Розглянемо кожен компонент детальніше.
Скрипти контенту
Кожен скрипт контенту має прямий доступ до DOM однієї веб-сторінки і, отже, піддається потенційно шкідливому вводу. Однак скрипт контенту не має жодних дозволів, окрім можливості надсилати повідомлення до ядра розширення.
Ядро розширення
Ядро розширення містить більшість привілеїв/доступу розширення, але ядро розширення може взаємодіяти з веб-контентом лише через XMLHttpRequest та скрипти контенту. Крім того, ядро розширення не має прямого доступу до хост-машини.
Рідний бінарний файл
Розширення дозволяє рідний бінарний файл, який може доступатися до хост-машини з повними привілеями користувача. Рідний бінарний файл взаємодіє з ядром розширення через стандартний Інтерфейс програмування додатків плагінів Netscape (NPAPI), який використовується Flash та іншими плагінами браузера.
Межі
{% hint style="danger" %} Щоб отримати повні привілеї користувача, зловмисник повинен переконати розширення передати шкідливий ввід від скрипту контенту до ядра розширення та від ядра розширення до рідного бінарного файлу. {% endhint %}
Кожен компонент розширення відокремлений один від одного сильними захисними межами. Кожен компонент працює в окремому процесі операційної системи. Скрипти контенту та ядра розширення працюють у пісочницях, недоступних для більшості служб операційної системи.
Більше того, скрипти контенту відокремлені від своїх асоційованих веб-сторінок, працюючи в окремій купі JavaScript. Скрипт контенту та веб-сторінка мають доступ до одного й того ж базового DOM, але обидва ніколи не обмінюються вказівниками JavaScript, що запобігає витоку функціональності JavaScript.
manifest.json
Розширення Chrome - це просто ZIP-папка з .crx розширенням файлу. Ядро розширення - це manifest.json
файл у корені папки, який вказує макет, дозволи та інші параметри конфігурації.
Приклад:
{
"manifest_version": 2,
"name": "My extension",
"version": "1.0",
"permissions": [
"storage"
],
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
"background": {
"scripts": [
"background.js"
]
},
"options_ui": {
"page": "options.html"
}
}
content_scripts
Скрипти контенту завантажуються щоразу, коли користувач переміщується на відповідну сторінку, у нашому випадку будь-яка сторінка, що відповідає виразу https://example.com/*
і не відповідає регулярному виразу *://*/*/business*
. Вони виконуються як власні скрипти сторінки і мають довільний доступ до Document Object Model (DOM) сторінки.
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Щоб включити або виключити більше URL-адрес, також можна використовувати include_globs
та exclude_globs
.
Це приклад контентного скрипта, який додасть кнопку пояснення на сторінку, коли 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);
});
Повідомлення надсилається на сторінки розширення скриптом контенту, коли натискається ця кнопка, через використання runtime.sendMessage() API. Це пов'язано з обмеженнями скрипта контенту в прямому доступі до API, з storage
, що є одним з небагатьох винятків. Для функціональностей, що виходять за межі цих винятків, повідомлення надсилаються на сторінки розширення, з якими можуть спілкуватися скрипти контенту.
{% hint style="warning" %}
Залежно від браузера, можливості скрипта контенту можуть трохи відрізнятися. Для браузерів на базі Chromium список можливостей доступний у документації Chrome Developers, а для Firefox основним джерелом є MDN.
Також варто зазначити, що скрипти контенту мають можливість спілкуватися зі скриптами фону, що дозволяє їм виконувати дії та передавати відповіді назад.
{% endhint %}
Для перегляду та налагодження скриптів контенту в Chrome меню інструментів розробника можна відкрити з Options > More tools > Developer tools АБО натиснувши Ctrl + Shift + I.
Після відображення інструментів розробника потрібно натиснути на вкладку Source, а потім на вкладку Content Scripts. Це дозволяє спостерігати за запущеними скриптами контенту з різних розширень та встановлювати точки зупинки для відстеження потоку виконання.
Впроваджені скрипти контенту
{% hint style="success" %}
Зверніть увагу, що скрипти контенту не є обов'язковими, оскільки також можливо динамічно впроваджувати скрипти та програмно впроваджувати їх на веб-сторінках через tabs.executeScript
. Це насправді забезпечує більше докладних контролів.
{% endhint %}
Для програмного впровадження скрипта контенту розширення повинно мати дозволи хоста для сторінки, на яку потрібно впровадити скрипти. Ці дозволи можуть бути отримані або запитуючи їх в маніфесті розширення, або на тимчасовій основі через activeTab.
Приклад розширення на основі activeTab
{% code title="manifest.json" %}
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
{% endcode %}
- Впровадити 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, але до того, як підресурси, такі як зображення та фрейми, завантажилися.
Via 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
Повідомлення, надіслані скриптами контенту, отримуються фоновою сторінкою, яка відіграє центральну роль у координації компонентів розширення. Зокрема, фонову сторінку зберігається протягом усього життя розширення, працюючи непомітно без прямої взаємодії з користувачем. Вона має власну модель об'єктів документа (DOM), що дозволяє здійснювати складні взаємодії та управління станом.
Ключові моменти:
- Роль фонової сторінки: Виконує функцію нервового центру для розширення, забезпечуючи зв'язок і координацію між різними частинами розширення.
- Постійність: Це завжди присутня сутність, невидима для користувача, але важлива для функціональності розширення.
- Автоматичне створення: Якщо не визначено явно, браузер автоматично створить фонову сторінку. Ця автоматично згенерована сторінка міститиме всі фонові скрипти, зазначені в маніфесті розширення, забезпечуючи безперебійну роботу фонових завдань розширення.
{% hint style="success" %} Зручність, яку надає браузер, автоматично створюючи фонову сторінку (коли не оголошено явно), забезпечує інтеграцію та функціонування всіх необхідних фонових скриптів, спрощуючи процес налаштування розширення. {% endhint %}
Приклад фонового скрипту:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
{
if (request == "explain")
{
chrome.tabs.create({ url: "https://example.net/explanation" });
}
})
Він використовує runtime.onMessage API для прослуховування повідомлень. Коли отримується повідомлення "explain"
, він використовує tabs API для відкриття сторінки в новій вкладці.
Щоб налагодити фоновий скрипт, ви можете перейти до деталей розширення та перевірити сервісний робітник, це відкриє інструменти розробника з фоновим скриптом:
Сторінки параметрів та інше
Розширення браузера можуть містити різні види сторінок:
- Сторінки дій відображаються у випадному меню, коли натискається іконка розширення.
- Сторінки, які розширення буде завантажувати в новій вкладці.
- Сторінки параметрів: Ця сторінка відображається поверх розширення при натисканні. У попередньому маніфесті в моєму випадку я зміг отримати доступ до цієї сторінки за адресою
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
або натиснувши:
Зверніть увагу, що ці сторінки не є постійними, як фонові сторінки, оскільки вони динамічно завантажують вміст за необхідності. Незважаючи на це, вони мають певні можливості з фоновою сторінкою:
- Зв'язок з контентними скриптами: Подібно до фонової сторінки, ці сторінки можуть отримувати повідомлення від контентних скриптів, що полегшує взаємодію в межах розширення.
- Доступ до специфічних для розширення API: Ці сторінки мають всебічний доступ до специфічних для розширення API, залежно від дозволів, визначених для розширення.
permissions
& host_permissions
permissions
та host_permissions
є записами з manifest.json
, які вказують які дозволи має розширення браузера (сховище, місцезнаходження...) і на яких веб-сторінках.
Оскільки розширення браузера можуть бути такими привілейованими, зловмисне або скомпрометоване може дозволити зловмиснику різні способи викрадення чутливої інформації та шпигунства за користувачем.
Перевірте, як працюють ці налаштування і як їх можна зловживати в:
{% content-ref url="browext-permissions-and-host_permissions.md" %} browext-permissions-and-host_permissions.md {% endcontent-ref %}
content_security_policy
Політику безпеки вмісту також можна оголосити всередині manifest.json
. Якщо вона визначена, вона може бути вразливою.
За замовчуванням налаштування для сторінок розширення браузера є досить обмежувальними:
script-src 'self'; object-src 'self';
Для отримання додаткової інформації про CSP та потенційні обходи, перегляньте:
{% content-ref url="../content-security-policy-csp-bypass/" %} content-security-policy-csp-bypass {% endcontent-ref %}
web_accessible_resources
щоб веб-сторінка могла отримати доступ до сторінки розширення браузера, наприклад, .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 доступний:
Однак, якщо параметр manifest.json
use_dynamic_url
використовується, цей id може бути динамічним.
{% hint style="success" %} Зверніть увагу, що навіть якщо сторінка згадується тут, вона може бути захищена від ClickJacking завдяки Content Security Policy. Тому вам також потрібно перевірити це (розділ frame-ancestors), перш ніж підтверджувати, що атака ClickJacking можлива. {% endhint %}
Доступ до цих сторінок робить їх потенційно вразливими до ClickJacking:
{% content-ref url="browext-clickjacking.md" %} browext-clickjacking.md {% endcontent-ref %}
{% hint style="success" %} Дозволяючи завантажувати ці сторінки лише розширенням, а не випадковими URL, можна запобігти атакам ClickJacking. {% endhint %}
{% hint style="danger" %}
Зверніть увагу, що сторінки з web_accessible_resources
та інші сторінки розширення також можуть контактувати з фоновими скриптами. Тому, якщо одна з цих сторінок вразлива до XSS, це може відкрити більшу вразливість.
Більше того, зверніть увагу, що ви можете відкривати лише сторінки, вказані в web_accessible_resources
всередині iframe, але з нової вкладки можливо отримати доступ до будь-якої сторінки в розширенні, знаючи ID розширення. Тому, якщо XSS виявлено, зловживаючи тими ж параметрами, це може бути використано, навіть якщо сторінка не налаштована в web_accessible_resources
.
{% endhint %}
externally_connectable
Згідно з документацією, властивість маніфесту "externally_connectable"
оголошує які розширення та веб-сторінки можуть підключатися до вашого розширення через runtime.connect та runtime.sendMessage.
- Якщо ключ
externally_connectable
не оголошений у маніфесті вашого розширення або він оголошений як"ids": ["*"]
, всі розширення можуть підключатися, але жодні веб-сторінки не можуть підключатися. - Якщо вказані конкретні ID, як у
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
, тільки ці програми можуть підключатися. - Якщо вказані збіги, ці веб-додатки зможуть підключатися:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- Якщо вказано як порожнє:
"externally_connectable": {}
, жоден додаток або веб не зможе підключитися.
Чим менше розширень та URL-адрес, вказаних тут, тим менша площа атаки буде.
{% hint style="danger" %}
Якщо веб-сторінка вразлива до XSS або захоплення вказана в externally_connectable
, зловмисник зможе надсилати повідомлення безпосередньо до фонового скрипта, повністю обходячи Контентний скрипт та його CSP.
Отже, це дуже потужний обхід.
Більше того, якщо клієнт встановить шкідливе розширення, навіть якщо йому не дозволено спілкуватися з вразливим розширенням, воно може впроваджувати XSS дані на дозволеній веб-сторінці або зловживати WebRequest
або DeclarativeNetRequest
API для маніпуляції запитами на цільовому домені, змінюючи запит сторінки на JavaScript файл. (Зверніть увагу, що CSP на цільовій сторінці може запобігти цим атакам). Ця ідея походить з цього опису.
{% endhint %}
Підсумок комунікації
Розширення <--> Веб-додаток
Для комунікації між контентним скриптом та веб-сторінкою зазвичай використовуються повідомлення. Тому у веб-додатку ви зазвичай знайдете виклики функції 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 });
</details>
Також можливо надсилати повідомлення з фонового скрипта до контентного скрипта, розташованого в конкретній вкладці, викликавши **`chrome.tabs.sendMessage`**, де вам потрібно буде вказати **ID вкладки**, до якої потрібно надіслати повідомлення.
### Від дозволених `externally_connectable` до розширення
**Веб-додатки та зовнішні розширення браузера, дозволені** в конфігурації `externally_connectable`, можуть надсилати запити, використовуючи:
```javascript
chrome.runtime.sendMessage(extensionId, ...
Де потрібно згадати ідентифікатор розширення.
Native Messaging
Можливо, що фонові скрипти спілкуються з двійковими файлами всередині системи, які можуть бути схильні до критичних вразливостей, таких як RCE якщо це спілкування не буде належним чином захищене. Більше про це пізніше.
chrome.runtime.sendNativeMessage(
'com.my_company.my_application',
{text: 'Hello'},
function (response) {
console.log('Received ' + response);
}
);
Web ↔︎ Зв'язок скриптів контенту
Середовища, в яких працюють скрипти контенту, і де існують хост-сторінки, відокремлені одне від одного, що забезпечує ізоляцію. Незважаючи на цю ізоляцію, обидві сторони мають можливість взаємодіяти з Document Object Model (DOM) сторінки, спільним ресурсом. Щоб хост-сторінка могла взаємодіяти зі скриптом контенту або непрямо з розширенням через скрипт контенту, необхідно використовувати DOM, доступний обом сторонам, як канал зв'язку.
Повідомлення постів
{% code title="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);
{% endcode %}
{% code title="example.js" %}
document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);
{% endcode %}
Безпечна комунікація Post Message повинна перевіряти автентичність отриманого повідомлення, це можна зробити, перевіряючи:
event.isTrusted
: Це True тільки якщо подія була викликана дією користувача- Контентний скрипт може очікувати повідомлення тільки якщо користувач виконує якусь дію
- домен походження: може очікувати повідомлення тільки з дозволеного списку доменів.
- Якщо використовується regex, будьте дуже обережні
- Джерело:
received_message.source !== window
можна використовувати для перевірки, чи було повідомлення з того ж вікна, де слухає Контентний Скрипт.
Попередні перевірки, навіть якщо вони виконані, можуть бути вразливими, тому перевірте на наступній сторінці потенційні обходи Post Message:
{% content-ref url="../postmessage-vulnerabilities/" %} postmessage-vulnerabilities {% endcontent-ref %}
Iframe
Ще один можливий спосіб комунікації може бути через Iframe URLs, ви можете знайти приклад у:
{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}
DOM
Це не "точно" спосіб комунікації, але веб та контентний скрипт матимуть доступ до веб DOM. Тому, якщо контентний скрипт читає якусь інформацію з нього, довіряючи веб DOM, веб може модифікувати ці дані (тому що веб не повинен бути довіреним, або тому що веб вразливий до XSS) і скомпрометувати Контентний Скрипт.
Ви також можете знайти приклад DOM-орієнтованого XSS для компрометації розширення браузера у:
{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}
Комунікація Контентного Скрипта ↔︎ Фоновий Скрипт
Контентний Скрипт може використовувати функції runtime.sendMessage() або tabs.sendMessage() для відправки одноразового JSON-серіалізованого повідомлення.
Для обробки відповіді використовуйте повернутий Promise. Хоча, для зворотної сумісності, ви все ще можете передати callback як останній аргумент.
Відправка запиту з контентного скрипта виглядає так:
(async () => {
const response = await chrome.runtime.sendMessage({greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
Відправка запиту з розширення (зазвичай фоновий скрипт). Приклад того, як надіслати повідомлення до контент-скрипту у вибраній вкладці:
// 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()
для конкретної події, буде єдиною, яка зможе ефективно доставити відповідь. Будь-які подальші відповіді на ту ж подію не будуть враховані.
При створенні нових розширень слід віддавати перевагу промісам, а не зворотним викликам. Що стосується використання зворотних викликів, функція sendResponse()
вважається дійсною лише в тому випадку, якщо вона виконується безпосередньо в синхронному контексті або якщо обробник події вказує на асинхронну операцію, повертаючи true
. Якщо жоден з обробників не повертає true
або якщо функція sendResponse()
видаляється з пам'яті (збирається сміття), зворотний виклик, пов'язаний з функцією sendMessage()
, буде викликаний за замовчуванням.
Native Messaging
Розширення браузера також дозволяють спілкуватися з бінарними файлами в системі через 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 (використовуйте stdin і stdout), а allowed_origins
вказує на розширення, які можуть отримати доступ до нього (і не можуть мати символи підстановки).
Chrome/Chromium буде шукати цей json у деяких реєстрах Windows та деяких шляхах у macOS і Linux (більше інформації в документації).
{% hint style="success" %}
Розширення браузера також потребує дозволу nativeMessaing
, щоб мати можливість використовувати це спілкування.
{% endhint %}
Ось як виглядає код деякого фонового скрипта, що надсилає повідомлення до рідного додатку:
chrome.runtime.sendNativeMessage(
'com.my_company.my_application',
{text: 'Hello'},
function (response) {
console.log('Received ' + response);
}
);
У цьому блозі пропонується вразливий шаблон, що зловживає нативними повідомленнями:
- Розширення браузера має шаблон з підстановкою для контентного скрипта.
- Контентний скрипт передає повідомлення
postMessage
до фонової скрипта, використовуючиsendMessage
. - Фоновий скрипт передає повідомлення до нативного додатку, використовуючи
sendNativeMessage
. - Нативний додаток обробляє повідомлення небезпечно, що призводить до виконання коду.
І всередині нього пояснюється приклад переміщення з будь-якої сторінки до RCE, зловживаючи розширенням браузера.
Чутлива інформація в пам'яті/коді/буфері обміну
Якщо Розширення Браузера зберігає чутливу інформацію в своїй пам'яті, це може бути вивантажено (особливо на машинах Windows) і пошукано для цієї інформації.
Отже, пам'ять Розширення Браузера не повинна вважатися безпечною, і чутлива інформація, така як облікові дані або мнемонічні фрази, не повинна зберігатися.
Звичайно, не вставляйте чутливу інформацію в код, оскільки вона буде публічною.
Щоб вивантажити пам'ять з браузера, ви можете вивантажити пам'ять процесу або перейти до налаштувань розширення браузера, натиснувши Inspect pop-up
-> У розділі Memory
-> Take a snapshot
і CTRL+F
для пошуку чутливої інформації в знімку.
Більше того, надзвичайно чутлива інформація, така як мнемонічні ключі або паролі, не повинна дозволятися для копіювання в буфер обміну (або принаймні видаляти її з буфера обміну через кілька секунд), оскільки тоді процеси, що моніторять буфер обміну, зможуть їх отримати.
Завантаження розширення в браузері
- Завантажте Розширення Браузера та розпакуйте його.
- Перейдіть до
chrome://extensions/
і увімкнітьРежим розробника
. - Натисніть кнопку
Load unpacked
.
У Firefox перейдіть до about:debugging#/runtime/this-firefox
і натисніть кнопку Load Temporary Add-on
.
Отримання вихідного коду з магазину
Вихідний код розширення Chrome можна отримати різними способами. Нижче наведені детальні пояснення та інструкції для кожного варіанту.
Завантаження розширення як ZIP через командний рядок
Вихідний код розширення 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, який є проектом з відкритим вихідним кодом. Його можна встановити з Chrome Web Store. Вихідний код переглядача доступний у його репозиторії GitHub.
Перегляд виходу локально встановленого розширення
Розширення Chrome, встановлені локально, також можна перевірити. Ось як:
- Доступ до вашого локального профілю Chrome, відвідавши
chrome://version/
і знайдіть поле "Profile Path". - Перейдіть до підпапки
Extensions/
у каталозі профілю. - Ця папка містить всі встановлені розширення, зазвичай з їх вихідним кодом у читабельному форматі.
Щоб ідентифікувати розширення, ви можете зіставити їх 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 і перевірити їх маніфест-файли на потенційно вразливі ознаки. Наприклад, щоб перевірити розширення з більш ніж 25000 користувачів, content_scripts
та дозволом nativeMessaing
:
{% code overflow="wrap" %}
# 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')"
{% endcode %}
Перевірочний список безпеки
Навіть якщо розширення браузера має обмежену поверхню атаки, деякі з них можуть містити вразливості або потенційні поліпшення безпеки. Найбільш поширені з них:
- Обмежити якомога більше запитувані
permissions
- Обмежити якомога більше
host_permissions
- Використовуйте сильну
content_security_policy
- Обмежити якомога більше
externally_connectable
, якщо це не потрібно і можливо, не залишайте його за замовчуванням, вкажіть{}
- Якщо тут згадується URL, вразливий до XSS або захоплення, зловмисник зможе надсилати повідомлення безпосередньо до фонових скриптів. Дуже потужний обхід.
- Обмежити якомога більше
web_accessible_resources
, навіть порожні, якщо можливо. - Якщо
web_accessible_resources
не порожнє, перевірте на ClickJacking - Якщо будь-яка комунікація відбувається з розширення до веб-сторінки, перевірте на XSS вразливості, викликані в комунікації.
- Якщо використовуються повідомлення Post, перевірте на вразливості Post Message.
- Якщо Content Script отримує доступ до деталей DOM, перевірте, що вони не вводять XSS, якщо їх модифікують веб
- Зробіть особливий акцент, якщо ця комунікація також залучена в комунікацію Content Script -> Background script
- Якщо фоновий скрипт спілкується через native messaging, перевірте, що комунікація є безпечною та очищеною
- Чутливу інформацію не слід зберігати всередині коду розширення браузера
- Чутливу інформацію не слід зберігати всередині пам'яті розширення браузера
- Чутливу інформацію не слід зберігати всередині файлової системи без захисту
Інструменти
Tarnish
- Завантажує будь-яке розширення Chrome з наданого посилання на веб-магазин Chrome.
- manifest.json переглядач: просто відображає версію JSON з форматуванням маніфесту розширення.
- Аналіз відбитків: Виявлення web_accessible_resources та автоматичне генерування JavaScript для відбитків розширення Chrome.
- Аналіз потенційного Clickjacking: Виявлення HTML-сторінок розширення з встановленою директивою web_accessible_resources. Вони можуть бути вразливими до clickjacking в залежності від мети сторінок.
- Переглядач попереджень про дозволи: який показує список усіх попереджень про запити дозволів Chrome, які будуть відображені при спробі користувача встановити розширення.
- Небезпечні функції: показує місце розташування небезпечних функцій, які можуть бути потенційно використані зловмисником (наприклад, функції, такі як innerHTML, chrome.tabs.executeScript).
- Точки входу: показує, де розширення приймає вхідні дані від користувача/зовнішніх джерел. Це корисно для розуміння поверхні розширення та пошуку потенційних точок для надсилання зловмисно створених даних до розширення.
- Як сканери Небезпечних функцій, так і Точок входу мають наступне для своїх згенерованих сповіщень:
- Відповідний фрагмент коду та рядок, що викликав сповіщення.
- Опис проблеми.
- Кнопка "Переглянути файл" для перегляду повного вихідного файлу, що містить код.
- Шлях до сповіщеного файлу.
- Повний URI розширення Chrome сповіщеного файлу.
- Тип файлу, наприклад, скрипт фонової сторінки, скрипт контенту, браузерна дія тощо.
- Якщо вразливий рядок знаходиться в JavaScript-файлі, шляхи всіх сторінок, де він включений, а також тип цих сторінок і статус web_accessible_resource.
- Аналізатор політики безпеки контенту (CSP) та перевірка обходу: Це вказує на слабкі місця в CSP вашого розширення та також висвітлює будь-які потенційні способи обійти ваш CSP через білий список CDN тощо.
- Відомі вразливі бібліотеки: Це використовує Retire.js для перевірки наявності використання відомих вразливих JavaScript-бібліотек.
- Завантажити розширення та відформатовані версії.
- Завантажити оригінальне розширення.
- Завантажити покращену версію розширення (автоформатований HTML та JavaScript).
- Автоматичне кешування результатів сканування, запуск сканування розширення займе певний час при першому запуску. Однак, при другому запуску, якщо розширення не було оновлено, це буде майже миттєво через кешовані результати.
- Посилання на звіти, які легко поділитися з кимось іншим, на звіт про розширення, згенерований tarnish.
Neto
Проект Neto - це пакет Python 3, призначений для аналізу та розкриття прихованих функцій плагінів і розширень браузера для відомих браузерів, таких як Firefox і Chrome. Він автоматизує процес розпакування упакованих файлів для вилучення цих функцій з відповідних ресурсів у розширенні, таких як manifest.json
, папки локалізації або вихідні файли Javascript і HTML.
Посилання
- Дякуємо @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
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.