hacktricks/pentesting-web/browser-extension-pentesting-methodology
2024-07-31 09:35:52 +00:00
..
browext-clickjacking.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:12:53 +00:00
browext-permissions-and-host_permissions.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-19 16:12:53 +00:00
browext-xss-example.md Translated ['generic-methodologies-and-resources/basic-forensic-methodol 2024-07-19 10:13:33 +00:00
README.md Translated ['pentesting-web/browser-extension-pentesting-methodology/REA 2024-07-31 09:35:52 +00:00

Browser Extension Pentesting Methodology

{% 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
{% endhint %}

Grundinformationen

Browsererweiterungen sind in JavaScript geschrieben und werden vom Browser im Hintergrund geladen. Sie haben ihr eigenes DOM, können jedoch mit den DOMs anderer Seiten interagieren. Das bedeutet, dass sie die Vertraulichkeit, Integrität und Verfügbarkeit (CIA) anderer Seiten gefährden können.

Hauptkomponenten

Die Layouts von Erweiterungen sehen am besten aus, wenn sie visualisiert werden, und bestehen aus drei Komponenten. Lassen Sie uns jede Komponente im Detail betrachten.

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

Inhalts-Skripte

Jedes Inhalts-Skript hat direkten Zugriff auf das DOM einer einzelnen Webseite und ist damit potenziell schädlichem Input ausgesetzt. Das Inhalts-Skript enthält jedoch keine Berechtigungen, außer der Fähigkeit, Nachrichten an den Erweiterungskern zu senden.

Erweiterungskern

Der Erweiterungskern enthält die meisten Berechtigungen/Zugriffe der Erweiterung, kann jedoch nur über XMLHttpRequest und Inhalts-Skripte mit Webinhalten interagieren. Außerdem hat der Erweiterungskern keinen direkten Zugriff auf die Hostmaschine.

Native Binary

Die Erweiterung erlaubt eine native Binärdatei, die auf die Hostmaschine mit den vollständigen Berechtigungen des Benutzers zugreifen kann. Die native Binärdatei interagiert über die standardmäßige Netscape Plugin Application Programming Interface (NPAPI), die von Flash und anderen Browser-Plug-ins verwendet wird, mit dem Erweiterungskern.

Grenzen

{% hint style="danger" %} Um die vollständigen Berechtigungen des Benutzers zu erhalten, muss ein Angreifer die Erweiterung überzeugen, schädlichen Input vom Inhalts-Skript an den Kern der Erweiterung und vom Kern der Erweiterung an die native Binärdatei weiterzugeben. {% endhint %}

Jede Komponente der Erweiterung ist durch starke Schutzgrenzen voneinander getrennt. Jede Komponente läuft in einem separaten Betriebssystemprozess. Inhalts-Skripte und Erweiterungskerne laufen in Sandbox-Prozessen, die für die meisten Betriebssystemdienste nicht verfügbar sind.

Darüber hinaus sind Inhalts-Skripte von ihren zugehörigen Webseiten getrennt, indem sie in einem separaten JavaScript-Heap ausgeführt werden. Das Inhalts-Skript und die Webseite haben Zugriff auf dasselbe zugrunde liegende DOM, aber die beiden tauschen niemals JavaScript-Zeiger aus, was das Leaken von JavaScript-Funktionalität verhindert.

manifest.json

Eine Chrome-Erweiterung ist einfach ein ZIP-Ordner mit einer .crx-Dateiendung. Der Kern der Erweiterung ist die manifest.json-Datei im Stammordner, die Layout, Berechtigungen und andere Konfigurationsoptionen angibt.

Beispiel:

{
"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-Skripte werden geladen, wann immer der Benutzer zu einer übereinstimmenden Seite navigiert, in unserem Fall zu jeder Seite, die dem https://example.com/* Ausdruck entspricht und nicht dem *://*/*/business* Regex entspricht. Sie werden wie die eigenen Skripte der Seite ausgeführt und haben beliebigen Zugriff auf das Document Object Model (DOM) der Seite.

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

Um weitere URLs einzuschließen oder auszuschließen, ist es auch möglich, include_globs und exclude_globs zu verwenden.

Dies ist ein Beispielinhaltsskript, das einen Erklärungsbutton zur Seite hinzufügt, wenn die Storage-API verwendet wird, um den message-Wert aus dem Speicher der Erweiterung abzurufen.

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);
});

Eine Nachricht wird an die Erweiterungsseiten vom Inhalts-Skript gesendet, wenn dieser Button geklickt wird, durch die Nutzung der runtime.sendMessage() API. Dies liegt an der Einschränkung des Inhalts-Skripts im direkten Zugriff auf APIs, wobei storage eine der wenigen Ausnahmen ist. Für Funktionalitäten über diese Ausnahmen hinaus werden Nachrichten an Erweiterungsseiten gesendet, mit denen Inhalts-Skripte kommunizieren können.

{% hint style="warning" %} Je nach Browser können die Fähigkeiten des Inhalts-Skripts leicht variieren. Für Chromium-basierte Browser ist die Liste der Fähigkeiten in der Chrome Developers-Dokumentation verfügbar, und für Firefox dient die MDN als primäre Quelle.
Es ist auch erwähnenswert, dass Inhalts-Skripte die Fähigkeit haben, mit Hintergrund-Skripten zu kommunizieren, was es ihnen ermöglicht, Aktionen auszuführen und Antworten zurückzugeben. {% endhint %}

Um Inhalts-Skripte in Chrome anzuzeigen und zu debuggen, kann das Menü der Chrome-Entwicklertools über Optionen > Weitere Tools > Entwicklertools oder durch Drücken von Ctrl + Shift + I aufgerufen werden.

Sobald die Entwicklertools angezeigt werden, ist der Reiter Quelle anzuklicken, gefolgt vom Reiter Inhalts-Skripte. Dies ermöglicht die Beobachtung von laufenden Inhalts-Skripten aus verschiedenen Erweiterungen und das Setzen von Haltepunkten, um den Ausführungsfluss zu verfolgen.

Eingespritzte Inhalts-Skripte

{% hint style="success" %} Beachten Sie, dass Inhalts-Skripte nicht zwingend erforderlich sind, da es auch möglich ist, Skripte dynamisch zu injizieren und sie programmgesteuert in Webseiten über tabs.executeScript zu injizieren. Dies bietet tatsächlich mehr granulare Kontrollen. {% endhint %}

Für die programmgesteuerte Injektion eines Inhalts-Skripts muss die Erweiterung Host-Berechtigungen für die Seite haben, in die die Skripte injiziert werden sollen. Diese Berechtigungen können entweder durch Anforderung innerhalb des Manifests der Erweiterung oder vorübergehend über activeTab gesichert werden.

Beispiel für eine activeTab-basierte Erweiterung

{% code title="manifest.json" %}

{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}

{% endcode %}

  • Eine JS-Datei beim Klicken injizieren:
// 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"]
});
});
  • Funktion bei Klick injizieren:
//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,
});
});

Beispiel mit Skriptberechtigungen

// 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" });

Um weitere URLs einzuschließen oder auszuschließen, ist es auch möglich, include_globs und exclude_globs zu verwenden.

Content Scripts run_at

Das Feld run_at steuert wann JavaScript-Dateien in die Webseite injiziert werden. Der bevorzugte und Standardwert ist "document_idle".

Die möglichen Werte sind:

  • document_idle: Wann immer möglich
  • document_start: Nach allen Dateien von css, aber bevor andere DOM-Elemente erstellt oder andere Skripte ausgeführt werden.
  • document_end: Unmittelbar nachdem das DOM vollständig ist, aber bevor Unterressourcen wie Bilder und Frames geladen wurden.

Via manifest.json

{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}

Über service-worker.js

chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.example.com/*" ],
runAt : "document_idle",
js : [ "contentScript.js" ],
}]);

background

Nachrichten, die von Inhalts-Skripten gesendet werden, werden von der Hintergrundseite empfangen, die eine zentrale Rolle bei der Koordination der Komponenten der Erweiterung spielt. Bemerkenswerterweise bleibt die Hintergrundseite während der gesamten Lebensdauer der Erweiterung bestehen und arbeitet diskret ohne direkte Benutzerinteraktion. Sie verfügt über ihr eigenes Document Object Model (DOM), das komplexe Interaktionen und Zustandsverwaltung ermöglicht.

Wichtige Punkte:

  • Rolle der Hintergrundseite: Dient als Nervenzentrum für die Erweiterung und gewährleistet Kommunikation und Koordination zwischen den verschiedenen Teilen der Erweiterung.
  • Persistenz: Es ist eine ständig präsente Entität, die für den Benutzer unsichtbar, aber für die Funktionalität der Erweiterung unerlässlich ist.
  • Automatische Generierung: Wenn nicht ausdrücklich definiert, wird der Browser automatisch eine Hintergrundseite erstellen. Diese automatisch generierte Seite enthält alle Hintergrundskripte, die im Manifest der Erweiterung angegeben sind, und gewährleistet den nahtlosen Betrieb der Hintergrundaufgaben der Erweiterung.

{% hint style="success" %} Der Komfort, den der Browser bei der automatischen Generierung einer Hintergrundseite (wenn nicht ausdrücklich deklariert) bietet, stellt sicher, dass alle notwendigen Hintergrundskripte integriert und betriebsbereit sind, was den Einrichtungsprozess der Erweiterung vereinfacht. {% endhint %}

Beispiel für ein Hintergrundskript:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
{
if (request == "explain")
{
chrome.tabs.create({ url: "https://example.net/explanation" });
}
})

Es verwendet die runtime.onMessage API, um Nachrichten zu empfangen. Wenn eine "explain"-Nachricht empfangen wird, verwendet es die tabs API, um eine Seite in einem neuen Tab zu öffnen.

Um das Hintergrundskript zu debuggen, können Sie zu den Erweiterungsdetails gehen und den Dienstarbeiter inspizieren. Dies öffnet die Entwicklertools mit dem Hintergrundskript:

Optionsseiten und andere

Browsererweiterungen können verschiedene Arten von Seiten enthalten:

  • Aktionsseiten werden in einem Dropdown angezeigt, wenn das Erweiterungssymbol angeklickt wird.
  • Seiten, die die Erweiterung in einem neuen Tab lädt.
  • Optionsseiten: Diese Seite wird oben auf der Erweiterung angezeigt, wenn sie angeklickt wird. Im vorherigen Manifest konnte ich auf diese Seite zugreifen unter chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca oder durch Klicken:

Beachten Sie, dass diese Seiten nicht persistent sind wie Hintergrundseiten, da sie dynamisch Inhalte nach Bedarf laden. Trotz dessen teilen sie bestimmte Fähigkeiten mit der Hintergrundseite:

  • Kommunikation mit Inhalts-Skripten: Ähnlich wie die Hintergrundseite können diese Seiten Nachrichten von Inhalts-Skripten empfangen, was die Interaktion innerhalb der Erweiterung erleichtert.
  • Zugriff auf erweiterungsspezifische APIs: Diese Seiten haben umfassenden Zugriff auf erweiterungsspezifische APIs, vorbehaltlich der für die Erweiterung definierten Berechtigungen.

permissions & host_permissions

permissions und host_permissions sind Einträge aus der manifest.json, die anzeigen, welche Berechtigungen die Browsererweiterung hat (Speicher, Standort...) und in welchen Webseiten.

Da Browsererweiterungen so privilegiert sein können, könnte eine bösartige oder kompromittierte Erweiterung dem Angreifer verschiedene Mittel ermöglichen, um sensible Informationen zu stehlen und den Benutzer auszuspionieren.

Überprüfen Sie, wie diese Einstellungen funktionieren und wie sie missbraucht werden könnten in:

{% content-ref url="browext-permissions-and-host_permissions.md" %} browext-permissions-and-host_permissions.md {% endcontent-ref %}

content_security_policy

Eine Content-Sicherheitsrichtlinie kann auch innerhalb der manifest.json deklariert werden. Wenn eine definiert ist, könnte sie anfällig sein.

Die Standardeinstellung für Seiten von Browsererweiterungen ist eher restriktiv:

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

Für weitere Informationen zu CSP und potenziellen Umgehungen siehe:

{% content-ref url="../content-security-policy-csp-bypass/" %} content-security-policy-csp-bypass {% endcontent-ref %}

web_accessible_resources

Damit eine Webseite auf eine Seite einer Browsererweiterung zugreifen kann, beispielsweise eine .html-Seite, muss diese Seite im web_accessible_resources-Feld der manifest.json erwähnt werden.
Zum Beispiel:

{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}

Diese Seiten sind über URLs wie zugänglich:

chrome-extension://<extension-id>/message.html

In öffentlichen Erweiterungen ist die extension-id zugänglich:

Wenn jedoch der manifest.json Parameter use_dynamic_url verwendet wird, kann diese id dynamisch sein.

{% hint style="success" %} Beachten Sie, dass selbst wenn eine Seite hier erwähnt wird, sie möglicherweise gegen ClickJacking geschützt ist, dank der Content Security Policy. Daher müssen Sie dies auch überprüfen (frame-ancestors Abschnitt), bevor Sie bestätigen, dass ein ClickJacking-Angriff möglich ist. {% endhint %}

Der Zugriff auf diese Seiten macht sie potenziell anfällig für ClickJacking:

{% content-ref url="browext-clickjacking.md" %} browext-clickjacking.md {% endcontent-ref %}

{% hint style="success" %} Wenn diese Seiten nur von der Erweiterung und nicht von zufälligen URLs geladen werden dürfen, könnte dies ClickJacking-Angriffe verhindern. {% endhint %}

{% hint style="danger" %} Beachten Sie, dass die Seiten aus web_accessible_resources und andere Seiten der Erweiterung ebenfalls in der Lage sind, Hintergrundskripte zu kontaktieren. Wenn eine dieser Seiten anfällig für XSS ist, könnte dies eine größere Verwundbarkeit eröffnen.

Darüber hinaus beachten Sie, dass Sie nur Seiten, die in web_accessible_resources angegeben sind, innerhalb von iframes öffnen können, aber von einem neuen Tab aus ist es möglich, auf jede Seite in der Erweiterung zuzugreifen, wenn Sie die Erweiterungs-ID kennen. Daher könnte, wenn ein XSS gefunden wird, das dieselben Parameter missbraucht, dies auch ausgenutzt werden, selbst wenn die Seite nicht in web_accessible_resources konfiguriert ist. {% endhint %}

externally_connectable

Laut den Docs erklärt die "externally_connectable" Manifest-Eigenschaft, welche Erweiterungen und Webseiten sich über runtime.connect und runtime.sendMessage mit Ihrer Erweiterung verbinden können.

  • Wenn der externally_connectable Schlüssel nicht im Manifest Ihrer Erweiterung deklariert ist oder als "ids": ["*"] deklariert ist, können alle Erweiterungen verbinden, aber keine Webseiten können sich verbinden.
  • Wenn spezifische IDs angegeben sind, wie in "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], können nur diese Anwendungen sich verbinden.
  • Wenn Übereinstimmungen angegeben sind, können diese Webanwendungen sich verbinden:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
  • Wenn es als leer angegeben ist: "externally_connectable": {}, kann keine App oder Webseite eine Verbindung herstellen.

Je weniger Erweiterungen und URLs hier angegeben sind, desto kleiner wird die Angriffsfläche sein.

{% hint style="danger" %} Wenn eine Webseite, die anfällig für XSS oder Übernahme ist, in externally_connectable angegeben ist, kann ein Angreifer Nachrichten direkt an das Hintergrundskript senden, wodurch das Content-Skript und dessen CSP vollständig umgangen werden.

Daher ist dies ein sehr mächtiger Bypass.

Darüber hinaus, wenn der Client eine bösartige Erweiterung installiert, selbst wenn diese nicht erlaubt ist, mit der anfälligen Erweiterung zu kommunizieren, könnte sie XSS-Daten in eine erlaubte Webseite injizieren oder die WebRequest oder DeclarativeNetRequest APIs missbrauchen, um Anfragen auf einer gezielten Domain zu manipulieren und eine Anfrage für eine JavaScript-Datei zu ändern. (Beachten Sie, dass CSP auf der gezielten Seite diese Angriffe verhindern könnte). Diese Idee stammt aus diesem Bericht. {% endhint %}

Kommunikationsübersicht

Erweiterung <--> WebApp

Um zwischen dem Content-Skript und der Webseite zu kommunizieren, werden normalerweise Post-Nachrichten verwendet. Daher finden Sie in der Webanwendung normalerweise Aufrufe der Funktion window.postMessage und im Content-Skript Listener wie window.addEventListener. Beachten Sie jedoch, dass die Erweiterung auch mit der Webanwendung kommunizieren könnte, indem sie eine Post-Nachricht sendet (und daher sollte die Webseite dies erwarten) oder einfach die Webseite dazu bringt, ein neues Skript zu laden.

Innerhalb der Erweiterung

Normalerweise wird die Funktion chrome.runtime.sendMessage verwendet, um eine Nachricht innerhalb der Erweiterung zu senden (normalerweise vom background-Skript verarbeitet) und um sie zu empfangen und zu verarbeiten, wird ein Listener deklariert, der chrome.runtime.onMessage.addListener aufruft.

Es ist auch möglich, chrome.runtime.connect() zu verwenden, um eine persistente Verbindung anstelle von einzelnen Nachrichten zu senden. Es ist möglich, es zu verwenden, um Nachrichten zu senden und zu empfangen, wie im folgenden Beispiel:

chrome.runtime.connect() Beispiel ```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>

Es ist auch möglich, Nachrichten von einem Hintergrundskript an ein Inhaltskript zu senden, das sich in einem bestimmten Tab befindet, indem **`chrome.tabs.sendMessage`** aufgerufen wird, wobei Sie die **ID des Tabs** angeben müssen, an den die Nachricht gesendet werden soll.

### Von erlaubtem `externally_connectable` zur Erweiterung

**Webanwendungen und externe Browsererweiterungen, die in der `externally_connectable`-Konfiguration erlaubt sind**, können Anfragen senden mit:
```javascript
chrome.runtime.sendMessage(extensionId, ...

Wo es notwendig ist, die Erweiterungs-ID zu erwähnen.

Native Messaging

Es ist möglich, dass die Hintergrundskripte mit Binärdateien im System kommunizieren, die anfällig für kritische Sicherheitsanfälligkeiten wie RCEs sein könnten, wenn diese Kommunikation nicht ordnungsgemäß gesichert ist. Mehr dazu später.

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

Web ↔︎ Kommunikation zwischen Content-Skripten

Die Umgebungen, in denen Content-Skripte arbeiten und wo die Host-Seiten existieren, sind getrennt voneinander, was Isolation gewährleistet. Trotz dieser Isolation haben beide die Möglichkeit, mit dem Document Object Model (DOM) der Seite zu interagieren, einer gemeinsamen Ressource. Damit die Host-Seite mit dem Content-Skript oder indirekt mit der Erweiterung über das Content-Skript kommunizieren kann, ist es erforderlich, das DOM zu nutzen, das für beide Parteien als Kommunikationskanal zugänglich ist.

Post-Nachrichten

{% 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 %}

Eine sichere Post Message-Kommunikation sollte die Authentizität der empfangenen Nachricht überprüfen, dies kann durch folgende Punkte geschehen:

  • event.isTrusted: Dies ist nur dann True, wenn das Ereignis durch eine Benutzeraktion ausgelöst wurde.
  • Das Inhalts-Skript könnte eine Nachricht nur erwarten, wenn der Benutzer eine Aktion ausführt.
  • Ursprungsdomäne: könnte eine Nachricht nur von einer erlaubten Liste von Domänen erwarten.
  • Wenn ein Regex verwendet wird, seien Sie sehr vorsichtig.
  • Quelle: received_message.source !== window kann verwendet werden, um zu überprüfen, ob die Nachricht aus demselben Fenster stammt, in dem das Inhalts-Skript lauscht.

Die vorherigen Überprüfungen könnten, selbst wenn sie durchgeführt werden, anfällig sein, also überprüfen Sie auf der folgenden Seite potenzielle Post Message-Bypässe:

{% content-ref url="../postmessage-vulnerabilities/" %} postmessage-vulnerabilities {% endcontent-ref %}

Iframe

Ein weiterer möglicher Kommunikationsweg könnte über Iframe-URLs erfolgen, ein Beispiel finden Sie in:

{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}

DOM

Dies ist nicht "genau" ein Kommunikationsweg, aber das Web und das Inhalts-Skript haben Zugriff auf das Web-DOM. Wenn das Inhalts-Skript also Informationen daraus liest und das Web-DOM vertraut, könnte das Web diese Daten modifizieren (weil das Web nicht vertraut werden sollte oder weil das Web anfällig für XSS ist) und das Inhalts-Skript kompromittieren.

Ein Beispiel für ein DOM-basiertes XSS zur Kompromittierung einer Browsererweiterung finden Sie in:

{% content-ref url="browext-xss-example.md" %} browext-xss-example.md {% endcontent-ref %}

Kommunikation zwischen Inhalts-Skript ↔︎ Hintergrund-Skript

Ein Inhalts-Skript kann die Funktionen runtime.sendMessage() oder tabs.sendMessage() verwenden, um eine einmalige JSON-serialisierbare Nachricht zu senden.

Um die Antwort zu verarbeiten, verwenden Sie das zurückgegebene Promise. Obwohl Sie aus Gründen der Abwärtskompatibilität weiterhin einen Callback als letzten Parameter übergeben können.

Das Senden einer Anfrage von einem Inhalts-Skript sieht so aus:

(async () => {
const response = await chrome.runtime.sendMessage({greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();

Eine Anfrage von der Erweiterung senden (normalerweise ein Hintergrundskript). Beispiel, wie man eine Nachricht an das Inhaltskript im ausgewählten Tab sendet:

// 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);
})();

Am empfangenden Ende müssen Sie einen runtime.onMessage Ereignis-Listener einrichten, um die Nachricht zu verarbeiten. Dies sieht sowohl aus einem Inhalts-Skript als auch von einer Erweiterungsseite gleich aus.

// 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"});
}
);

Im hervorgehobenen Beispiel wurde sendResponse() synchron ausgeführt. Um den onMessage-Ereignis-Handler für die asynchrone Ausführung von sendResponse() zu modifizieren, ist es unerlässlich, return true; einzufügen.

Eine wichtige Überlegung ist, dass in Szenarien, in denen mehrere Seiten onMessage-Ereignisse empfangen sollen, die erste Seite, die sendResponse() für ein bestimmtes Ereignis ausführt, die einzige sein wird, die die Antwort effektiv liefern kann. Alle nachfolgenden Antworten auf dasselbe Ereignis werden nicht berücksichtigt.

Beim Erstellen neuer Erweiterungen sollte die Präferenz auf Promises anstelle von Callbacks liegen. In Bezug auf die Verwendung von Callbacks wird die Funktion sendResponse() nur dann als gültig angesehen, wenn sie direkt im synchronen Kontext ausgeführt wird oder wenn der Ereignis-Handler eine asynchrone Operation anzeigt, indem er true zurückgibt. Sollten keine der Handler true zurückgeben oder wenn die Funktion sendResponse() aus dem Speicher entfernt wird (garbage-collected), wird der mit der Funktion sendMessage() verbundene Callback standardmäßig ausgelöst.

Native Messaging

Browsererweiterungen ermöglichen auch die Kommunikation mit Binaries im System über stdin. Die Anwendung muss ein JSON installieren, das dies in einem JSON wie folgt angibt:

{
"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/"]
}

Wo der name der String ist, der an runtime.connectNative() oder runtime.sendNativeMessage() übergeben wird, um mit der Anwendung von den Hintergrundskripten der Browsererweiterung zu kommunizieren. Der path ist der Pfad zur Binärdatei, es gibt nur 1 gültigen type, der stdio ist (verwende stdin und stdout) und die allowed_origins geben die Erweiterungen an, die darauf zugreifen können (und dürfen kein Wildcard haben).

Chrome/Chromium wird nach diesem JSON in einigen Windows-Registrierungen und einigen Pfaden in macOS und Linux suchen (weitere Informationen in den docs).

{% hint style="success" %} Die Browsererweiterung benötigt auch die nativeMessaing-Berechtigung, um diese Kommunikation nutzen zu können. {% endhint %}

So sieht ein Hintergrundskriptcode aus, der Nachrichten an eine native Anwendung sendet:

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

In diesem Blogbeitrag wird ein verwundbares Muster vorgeschlagen, das native Nachrichten missbraucht:

  1. Die Browsererweiterung hat ein Wildcard-Muster für das Inhalts-Skript.
  2. Das Inhalts-Skript überträgt postMessage-Nachrichten an das Hintergrund-Skript mit sendMessage.
  3. Das Hintergrund-Skript überträgt die Nachricht an die native Anwendung mit sendNativeMessage.
  4. Die native Anwendung verarbeitet die Nachricht gefährlich, was zu einer Codeausführung führt.

Und darin wird ein Beispiel für den Übergang von jeder Seite zu RCE unter Ausnutzung einer Browsererweiterung erklärt.

Sensible Informationen im Speicher/Code/Clipboard

Wenn eine Browsererweiterung sensible Informationen im Speicher speichert, könnten diese ausgelesen werden (insbesondere auf Windows-Maschinen) und nach diesen Informationen gesucht werden.

Daher sollte der Speicher der Browsererweiterung nicht als sicher betrachtet werden und sensible Informationen wie Anmeldeinformationen oder mnemonische Phrasen sollten nicht gespeichert werden.

Natürlich sollten keine sensiblen Informationen im Code platziert werden, da sie öffentlich sein werden.

Um den Speicher des Browsers auszulesen, könnten Sie den Prozessspeicher auslesen oder zu den Einstellungen der Browsererweiterung gehen, auf Pop-up inspizieren klicken -> Im Speicher-Bereich -> Snapshot erstellen und STRG+F verwenden, um im Snapshot nach sensiblen Informationen zu suchen.

Darüber hinaus sollten hochsensible Informationen wie mnemonische Schlüssel oder Passwörter nicht in die Zwischenablage kopiert werden dürfen (oder zumindest innerhalb weniger Sekunden aus der Zwischenablage entfernt werden), da Prozesse, die die Zwischenablage überwachen, sie dann erhalten können.

Laden einer Erweiterung im Browser

  1. Laden Sie die Browsererweiterung herunter und entpacken Sie sie.
  2. Gehen Sie zu chrome://extensions/ und aktivieren Sie den Entwicklermodus.
  3. Klicken Sie auf die Schaltfläche Entpackte Erweiterung laden.

In Firefox gehen Sie zu about:debugging#/runtime/this-firefox und klicken auf die Schaltfläche Temporäre Erweiterung laden.

Den Quellcode aus dem Store abrufen

Der Quellcode einer Chrome-Erweiterung kann auf verschiedene Weise abgerufen werden. Nachfolgend sind detaillierte Erklärungen und Anweisungen für jede Option aufgeführt.

Erweiterung als ZIP über die Befehlszeile herunterladen

Der Quellcode einer Chrome-Erweiterung kann über die Befehlszeile als ZIP-Datei heruntergeladen werden. Dies beinhaltet die Verwendung von curl, um die ZIP-Datei von einer bestimmten URL abzurufen und dann den Inhalt der ZIP-Datei in ein Verzeichnis zu extrahieren. Hier sind die Schritte:

  1. Ersetzen Sie "extension_id" durch die tatsächliche ID der Erweiterung.
  2. Führen Sie die folgenden Befehle aus:
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"

Verwenden Sie die CRX Viewer-Website

https://robwu.nl/crxviewer/

Verwenden Sie die CRX Viewer-Erweiterung

Eine weitere praktische Methode ist die Verwendung des Chrome Extension Source Viewers, einem Open-Source-Projekt. Es kann aus dem Chrome Web Store installiert werden. Der Quellcode des Viewers ist in seinem GitHub-Repository verfügbar.

Quellcode der lokal installierten Erweiterung anzeigen

Chrome-Erweiterungen, die lokal installiert sind, können ebenfalls inspiziert werden. So geht's:

  1. Greifen Sie auf Ihr lokales Chrome-Profilverzeichnis zu, indem Sie chrome://version/ besuchen und das Feld "Profilpfad" finden.
  2. Navigieren Sie zum Unterordner Extensions/ innerhalb des Profilverzeichnisses.
  3. Dieser Ordner enthält alle installierten Erweiterungen, typischerweise mit ihrem Quellcode in einem lesbaren Format.

Um Erweiterungen zu identifizieren, können Sie deren IDs den Namen zuordnen:

  • Aktivieren Sie den Entwicklermodus auf der Seite about:extensions, um die IDs jeder Erweiterung zu sehen.
  • Innerhalb des Ordners jeder Erweiterung enthält die Datei manifest.json ein lesbares name-Feld, das Ihnen hilft, die Erweiterung zu identifizieren.

Verwenden Sie einen Dateiarchivier oder -depacker

Gehen Sie zum Chrome Web Store und laden Sie die Erweiterung herunter. Die Datei hat die Erweiterung .crx. Ändern Sie die Dateierweiterung von .crx in .zip. Verwenden Sie einen beliebigen Dateiarchivier (wie WinRAR, 7-Zip usw.), um den Inhalt der ZIP-Datei zu extrahieren.

Entwicklermodus in Chrome verwenden

Öffnen Sie Chrome und gehen Sie zu chrome://extensions/. Aktivieren Sie "Entwicklermodus" oben rechts. Klicken Sie auf "Entpackte Erweiterung laden...". Navigieren Sie zum Verzeichnis Ihrer Erweiterung. Dies lädt den Quellcode nicht herunter, ist jedoch nützlich, um den Code einer bereits heruntergeladenen oder entwickelten Erweiterung anzuzeigen und zu ändern.

Chrome-Erweiterungsmanifest-Datensatz

Um zu versuchen, anfällige Browsererweiterungen zu erkennen, können Sie das https://github.com/palant/chrome-extension-manifests-dataset verwenden und deren Manifestdateien auf potenziell anfällige Anzeichen überprüfen. Zum Beispiel, um nach Erweiterungen mit mehr als 25000 Benutzern, content_scripts und der Berechtigung nativeMessaging zu suchen:

{% 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 %}

Sicherheitsprüfliste

Obwohl Browsererweiterungen eine begrenzte Angriffsfläche haben, können einige von ihnen Schwachstellen oder potenzielle Verbesserungen aufweisen. Die folgenden sind die häufigsten:

  • Berechtigungen so weit wie möglich einschränken
  • Host-Berechtigungen so weit wie möglich einschränken
  • Verwenden Sie eine starke content_security_policy
  • Einschränken Sie so weit wie möglich die externally_connectable, wenn keine benötigt wird und möglich ist, lassen Sie es nicht standardmäßig, geben Sie {} an
  • Wenn hier eine URL, die anfällig für XSS oder Übernahme ist, erwähnt wird, kann ein Angreifer Nachrichten direkt an die Hintergrundskripte senden. Sehr mächtiger Umgehung.
  • Einschränken Sie so weit wie möglich die web_accessible_resources, sogar leer, wenn möglich.
  • Wenn web_accessible_resources nicht leer ist, überprüfen Sie ClickJacking
  • Wenn eine Kommunikation von der Erweiterung zur Webseite erfolgt, überprüfen Sie auf XSS Schwachstellen, die in der Kommunikation verursacht werden.
  • Wenn Post-Nachrichten verwendet werden, überprüfen Sie auf Post-Nachrichten-Schwachstellen.
  • Wenn das Inhalts-Skript auf DOM-Details zugreift, überprüfen Sie, ob sie kein XSS einführen, wenn sie von der Webseite modifiziert werden
  • Legen Sie besonderen Wert darauf, wenn diese Kommunikation auch an der Kommunikation zwischen Inhalts-Skript und Hintergrundskript beteiligt ist
  • Wenn das Hintergrundskript über native Messaging kommuniziert, überprüfen Sie, ob die Kommunikation sicher und bereinigt ist
  • Sensible Informationen sollten nicht im Code der Browsererweiterung gespeichert werden
  • Sensible Informationen sollten nicht im Speicher der Browsererweiterung gespeichert werden
  • Sensible Informationen sollten nicht im Dateisystem ungeschützt gespeichert werden

Werkzeuge

Tarnish

  • Zieht jede Chrome-Erweiterung von einem bereitgestellten Chrome-Webstore-Link.
  • manifest.json Viewer: zeigt einfach eine JSON-hübsch formatierte Version des Manifests der Erweiterung an.
  • Fingerprint-Analyse: Erkennung von web_accessible_resources und automatische Generierung von JavaScript zur Fingerabdruckerkennung von Chrome-Erweiterungen.
  • Potenzielle Clickjacking-Analyse: Erkennung von HTML-Seiten der Erweiterung mit der web_accessible_resources-Richtlinie. Diese sind potenziell anfällig für Clickjacking, abhängig vom Zweck der Seiten.
  • Berechtigungswarnungen Viewer: zeigt eine Liste aller Chrome-Berechtigungsaufforderungswarnungen, die angezeigt werden, wenn ein Benutzer versucht, die Erweiterung zu installieren.
  • Gefährliche Funktion(en): zeigt den Standort gefährlicher Funktionen, die potenziell von einem Angreifer ausgenutzt werden könnten (z. B. Funktionen wie innerHTML, chrome.tabs.executeScript).
  • Einstiegspunkt(e): zeigt, wo die Erweiterung Benutzereingaben oder externe Eingaben entgegennimmt. Dies ist nützlich, um die Angriffsfläche einer Erweiterung zu verstehen und nach potenziellen Punkten zu suchen, um bösartig gestaltete Daten an die Erweiterung zu senden.
  • Sowohl die Scanner für gefährliche Funktion(en) als auch Einstiegspunkt(e) haben Folgendes für ihre generierten Warnungen:
  • Relevanter Codeausschnitt und Zeile, die die Warnung verursacht hat.
  • Beschreibung des Problems.
  • Eine Schaltfläche „Datei anzeigen“, um die vollständige Quelldatei mit dem Code anzuzeigen.
  • Der Pfad der gewarnten Datei.
  • Die vollständige Chrome-Erweiterungs-URI der gewarnten Datei.
  • Den Typ der Datei, z. B. ein Hintergrundseiten-Skript, Inhalts-Skript, Browser-Aktion usw.
  • Wenn die anfällige Zeile in einer JavaScript-Datei ist, die Pfade aller Seiten, auf denen sie enthalten ist, sowie den Typ dieser Seiten und den Status der web_accessible_resource.
  • Content Security Policy (CSP) Analyzer und Umgehungsprüfer: Dies wird Schwächen in der CSP Ihrer Erweiterung aufzeigen und auch potenzielle Möglichkeiten zur Umgehung Ihrer CSP aufgrund von aufgelisteten CDNs usw. aufzeigen.
  • Bekannte anfällige Bibliotheken: Dies verwendet Retire.js, um die Verwendung bekannter anfälliger JavaScript-Bibliotheken zu überprüfen.
  • Erweiterung und formatierte Versionen herunterladen.
  • Die originale Erweiterung herunterladen.
  • Eine verschönerte Version der Erweiterung herunterladen (automatisch hübsch formatierte HTML- und JavaScript).
  • Automatische Zwischenspeicherung der Scannergebnisse, das Ausführen eines Erweiterungsscans dauert beim ersten Ausführen eine gute Zeit. Beim zweiten Mal, vorausgesetzt, die Erweiterung wurde nicht aktualisiert, wird es fast sofort sein, da die Ergebnisse zwischengespeichert werden.
  • Verlinkbare Bericht-URLs, um jemand anderem leicht einen von Tarnish generierten Erweiterungsbericht zu verlinken.

Neto

Projekt Neto ist ein Python 3-Paket, das entwickelt wurde, um versteckte Funktionen von Browser-Plugins und -Erweiterungen für bekannte Browser wie Firefox und Chrome zu analysieren und zu entschlüsseln. Es automatisiert den Prozess des Entpackens der gepackten Dateien, um diese Funktionen aus relevanten Ressourcen in einer Erweiterung wie manifest.json, Lokalisierungsordnern oder JavaScript- und HTML-Quelldateien zu extrahieren.

Referenzen

{% hint style="success" %} Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks unterstützen
{% endhint %}