Browser Extension Pentesting Methodology
Last updated
Last updated
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)
Rozszerzenia przeglądarki są napisane w JavaScript i ładowane przez przeglądarkę w tle. Mają swój DOM, ale mogą wchodzić w interakcje z DOM-ami innych stron. Oznacza to, że mogą naruszać poufność, integralność i dostępność (CIA) innych stron.
Układy rozszerzeń wyglądają najlepiej, gdy są wizualizowane i składają się z trzech komponentów. Przyjrzyjmy się każdemu komponentowi dokładniej.
Każdy skrypt treści ma bezpośredni dostęp do DOM pojedynczej strony internetowej i jest narażony na potencjalnie złośliwe dane wejściowe. Jednak skrypt treści nie ma żadnych uprawnień poza możliwością wysyłania wiadomości do rdzenia rozszerzenia.
Rdzeń rozszerzenia zawiera większość uprawnień/dostępu rozszerzenia, ale rdzeń rozszerzenia może wchodzić w interakcje z treścią internetową tylko za pośrednictwem XMLHttpRequest i skryptów treści. Ponadto rdzeń rozszerzenia nie ma bezpośredniego dostępu do maszyny gospodarza.
Rozszerzenie pozwala na natychmiastowy plik binarny, który może uzyskać dostęp do maszyny gospodarza z pełnymi uprawnieniami użytkownika. Natychmiastowy plik binarny wchodzi w interakcje z rdzeniem rozszerzenia za pośrednictwem standardowego interfejsu programowania aplikacji Netscape Plugin (NPAPI), używanego przez Flash i inne wtyczki przeglądarki.
Aby uzyskać pełne uprawnienia użytkownika, atakujący musi przekonać rozszerzenie do przekazania złośliwych danych wejściowych ze skryptu treści do rdzenia rozszerzenia, a następnie z rdzenia rozszerzenia do natychmiastowego pliku binarnego.
Każdy komponent rozszerzenia jest oddzielony od siebie przez silne granice ochronne. Każdy komponent działa w osobnym procesie systemu operacyjnego. Skrypty treści i rdzenie rozszerzeń działają w procesach piaskownicy, niedostępnych dla większości usług systemu operacyjnego.
Co więcej, skrypty treści są oddzielone od swoich powiązanych stron internetowych przez działanie w osobnym stosie JavaScript. Skrypt treści i strona internetowa mają dostęp do tego samego podstawowego DOM, ale obie nigdy nie wymieniają wskaźników JavaScript, co zapobiega wyciekowi funkcjonalności JavaScript.
manifest.json
Rozszerzenie Chrome to po prostu folder ZIP z .crx file extension. Rdzeń rozszerzenia to plik manifest.json
w katalogu głównym folderu, który określa układ, uprawnienia i inne opcje konfiguracyjne.
Przykład:
content_scripts
Skrypty zawartości są ładowane za każdym razem, gdy użytkownik nawiguje do pasującej strony, w naszym przypadku każda strona pasująca do wyrażenia https://example.com/*
i niepasująca do wyrażenia regex *://*/*/business*
. Wykonują się jak własne skrypty strony i mają dowolny dostęp do Modelu Obiektów Dokumentu (DOM) strony.
Aby dodać lub wykluczyć więcej adresów URL, można również użyć include_globs
i exclude_globs
.
To jest przykład skryptu zawartości, który doda przycisk wyjaśnienia do strony, gdy API storage zostanie użyte do pobrania wartości message
z pamięci rozszerzenia.
Wiadomość jest wysyłana do stron rozszerzenia przez skrypt treści, gdy ten przycisk jest klikany, poprzez wykorzystanie runtime.sendMessage() API. Wynika to z ograniczenia skryptu treści w bezpośrednim dostępie do API, przy czym storage
jest jednym z nielicznych wyjątków. Dla funkcjonalności wykraczających poza te wyjątki, wiadomości są wysyłane do stron rozszerzenia, z którymi skrypty treści mogą komunikować się.
W zależności od przeglądarki, możliwości skryptu treści mogą się nieco różnić. Dla przeglądarek opartych na Chromium, lista możliwości jest dostępna w dokumentacji Chrome Developers, a dla Firefox, MDN służy jako główne źródło. Warto również zauważyć, że skrypty treści mają możliwość komunikacji z skryptami w tle, co umożliwia im wykonywanie działań i przekazywanie odpowiedzi z powrotem.
Aby wyświetlić i debugować skrypty treści w Chrome, menu narzędzi dewelopera można otworzyć z Opcje > Więcej narzędzi > Narzędzia dewelopera LUB naciskając Ctrl + Shift + I.
Po wyświetleniu narzędzi dewelopera, należy kliknąć na zakładkę Źródło, a następnie na zakładkę Skrypty treści. Umożliwia to obserwację działających skryptów treści z różnych rozszerzeń oraz ustawienie punktów przerwania w celu śledzenia przepływu wykonania.
Zauważ, że Skrypty Treści nie są obowiązkowe, ponieważ możliwe jest również dynamiczne wstrzykiwanie skryptów oraz programowe wstrzykiwanie ich na stronach internetowych za pomocą tabs.executeScript
. To w rzeczywistości zapewnia bardziej szczegółową kontrolę.
Aby programowo wstrzyknąć skrypt treści, rozszerzenie musi mieć uprawnienia hosta dla strony, do której skrypty mają być wstrzykiwane. Uprawnienia te mogą być zabezpieczone albo przez zażądanie ich w manifeście rozszerzenia, albo tymczasowo poprzez activeTab.
Wstrzyknij plik JS po kliknięciu:
Wstrzyknij funkcję po kliknięciu:
Aby dodać lub wykluczyć więcej adresów URL, można również użyć include_globs
i exclude_globs
.
run_at
Pole run_at
kontroluje kiedy pliki JavaScript są wstrzykiwane do strony internetowej. Preferowana i domyślna wartość to "document_idle"
.
Możliwe wartości to:
document_idle
: Kiedy tylko to możliwe
document_start
: Po załadowaniu jakichkolwiek plików z css
, ale przed skonstruowaniem jakiegokolwiek innego DOM lub uruchomieniem jakiegokolwiek innego skryptu.
document_end
: Natychmiast po zakończeniu DOM, ale przed załadowaniem subzasobów, takich jak obrazy i ramki.
manifest.json
Via service-worker.js
background
Wiadomości wysyłane przez skrypty zawartości są odbierane przez stronę tła, która odgrywa centralną rolę w koordynowaniu komponentów rozszerzenia. Co ważne, strona tła utrzymuje się przez cały czas życia rozszerzenia, działając dyskretnie bez bezpośredniej interakcji użytkownika. Posiada własny Model Obiektów Dokumentu (DOM), co umożliwia złożone interakcje i zarządzanie stanem.
Kluczowe punkty:
Rola strony tła: Działa jako centrum nerwowe dla rozszerzenia, zapewniając komunikację i koordynację między różnymi częściami rozszerzenia.
Trwałość: To zawsze obecny byt, niewidoczny dla użytkownika, ale integralny dla funkcjonalności rozszerzenia.
Automatyczne generowanie: Jeśli nie jest wyraźnie zdefiniowane, przeglądarka automatycznie utworzy stronę tła. Ta automatycznie generowana strona będzie zawierać wszystkie skrypty tła określone w manifeście rozszerzenia, zapewniając płynne działanie zadań tła rozszerzenia.
Wygoda zapewniana przez przeglądarkę w automatycznym generowaniu strony tła (gdy nie jest wyraźnie zadeklarowana) zapewnia, że wszystkie niezbędne skrypty tła są zintegrowane i działają, upraszczając proces konfiguracji rozszerzenia.
Przykładowy skrypt tła:
Używa runtime.onMessage API do nasłuchiwania wiadomości. Gdy otrzymana zostanie wiadomość "explain"
, używa tabs API do otwarcia strony w nowej karcie.
Aby debugować skrypt w tle, możesz przejść do szczegółów rozszerzenia i zbadać serwis worker, co otworzy narzędzia deweloperskie z skryptem w tle:
Rozszerzenia przeglądarki mogą zawierać różne rodzaje stron:
Strony akcji są wyświetlane w rozwijanym menu po kliknięciu na ikonę rozszerzenia.
Strony, które rozszerzenie załaduje w nowej karcie.
Strony opcji: Ta strona wyświetla się na górze rozszerzenia po kliknięciu. W poprzednim manifeście w moim przypadku mogłem uzyskać dostęp do tej strony w chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
lub klikając:
Zauważ, że te strony nie są trwałe jak strony w tle, ponieważ ładują dynamicznie treści w zależności od potrzeb. Mimo to, dzielą pewne możliwości z stroną w tle:
Komunikacja z skryptami treści: Podobnie jak strona w tle, te strony mogą otrzymywać wiadomości od skryptów treści, co ułatwia interakcję w ramach rozszerzenia.
Dostęp do specyficznych API rozszerzenia: Te strony mają pełny dostęp do specyficznych API rozszerzenia, w zależności od uprawnień zdefiniowanych dla rozszerzenia.
permissions
& host_permissions
permissions
i host_permissions
to wpisy z manifest.json
, które wskazują jakie uprawnienia ma rozszerzenie przeglądarki (przechowywanie, lokalizacja...) oraz na jakich stronach internetowych.
Ponieważ rozszerzenia przeglądarki mogą być tak uprzywilejowane, złośliwe lub skompromitowane mogłyby umożliwić atakującemu różne sposoby kradzieży wrażliwych informacji i szpiegowania użytkownika.
Sprawdź, jak te ustawienia działają i jak mogą być nadużywane w:
content_security_policy
Polityka bezpieczeństwa treści może być również zadeklarowana w manifest.json
. Jeśli jest zdefiniowana, może być wrażliwa.
Domyślne ustawienie dla stron rozszerzeń przeglądarki jest dość restrykcyjne:
Aby strona internetowa mogła uzyskać dostęp do strony rozszerzenia przeglądarki, na przykład strony .html
, ta strona musi być wymieniona w polu web_accessible_resources
pliku manifest.json
.
Na przykład:
Te strony są dostępne pod adresem URL jak:
W publicznych rozszerzeniach extension-id jest dostępny:
Jednakże, jeśli parametr manifest.json
use_dynamic_url
jest używany, to id może być dynamiczne.
Zauważ, że nawet jeśli strona jest tutaj wymieniona, może być chroniona przed ClickJacking dzięki Content Security Policy. Dlatego musisz to również sprawdzić (sekcja frame-ancestors) przed potwierdzeniem, że atak ClickJacking jest możliwy.
Dopuszczenie dostępu do tych stron sprawia, że te strony są potencjalnie podatne na ClickJacking:
Zezwolenie na ładowanie tych stron tylko przez rozszerzenie, a nie przez losowe adresy URL, może zapobiec atakom ClickJacking.
Zauważ, że strony z web_accessible_resources
oraz inne strony rozszerzenia są również zdolne do kontaktowania się z skryptami w tle. Jeśli jedna z tych stron jest podatna na XSS, może to otworzyć większą lukę.
Ponadto, zauważ, że możesz otworzyć tylko strony wskazane w web_accessible_resources
wewnątrz iframe, ale z nowej karty możliwe jest uzyskanie dostępu do dowolnej strony w rozszerzeniu, znając ID rozszerzenia. Dlatego, jeśli XSS zostanie znalezione, wykorzystując te same parametry, może być nadużyte, nawet jeśli strona nie jest skonfigurowana w web_accessible_resources
.
externally_connectable
Zgodnie z dokumentacją, właściwość manifestu "externally_connectable"
deklaruje które rozszerzenia i strony internetowe mogą łączyć się z Twoim rozszerzeniem za pomocą runtime.connect i runtime.sendMessage.
Jeśli klucz externally_connectable
nie jest zadeklarowany w manifeście Twojego rozszerzenia lub jest zadeklarowany jako "ids": ["*"]
, wszystkie rozszerzenia mogą się łączyć, ale żadne strony internetowe nie mogą się łączyć.
Jeśli określone ID są podane, jak w "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
, tylko te aplikacje mogą się łączyć.
Jeśli podano dopasowania, te aplikacje webowe będą mogły się łączyć:
Jeśli jest określone jako puste: "externally_connectable": {}
, żadna aplikacja ani strona internetowa nie będą mogły się połączyć.
Im mniej rozszerzeń i adresów URL wskazanych tutaj, tym mniejsza powierzchnia ataku.
Jeśli strona internetowa wrażliwa na XSS lub przejęcie jest wskazana w externally_connectable
, atakujący będzie mógł wysyłać wiadomości bezpośrednio do skryptu w tle, całkowicie omijając skrypt treści i jego CSP.
Dlatego jest to bardzo potężne obejście.
Co więcej, jeśli klient zainstaluje złośliwe rozszerzenie, nawet jeśli nie jest dozwolone do komunikacji z wrażliwym rozszerzeniem, może wstrzyknąć dane XSS w dozwolonej stronie internetowej lub nadużyć WebRequest
lub DeclarativeNetRequest
API, aby manipulować żądaniami na docelowej domenie, zmieniając żądanie strony dla pliku JavaScript. (Zauważ, że CSP na docelowej stronie może zapobiec tym atakom). Ten pomysł pochodzi z tego opisu.
Aby komunikować się między skryptem treści a stroną internetową, zazwyczaj używane są wiadomości post. Dlatego w aplikacji internetowej zazwyczaj znajdziesz wywołania funkcji window.postMessage
oraz w skrypcie treści nasłuchiwacze, takie jak window.addEventListener
. Należy jednak zauważyć, że rozszerzenie może również komunikować się z aplikacją internetową, wysyłając wiadomość Post (a zatem strona powinna się tego spodziewać) lub po prostu sprawić, by strona załadowała nowy skrypt.
Zazwyczaj funkcja chrome.runtime.sendMessage
jest używana do wysyłania wiadomości wewnątrz rozszerzenia (zazwyczaj obsługiwana przez skrypt background
), a aby ją odebrać i obsłużyć, deklarowany jest nasłuchiwacz wywołujący chrome.runtime.onMessage.addListener
.
Możliwe jest również użycie chrome.runtime.connect()
, aby mieć stałe połączenie zamiast wysyłania pojedynczych wiadomości, można go użyć do wysyłania i odbierania wiadomości, jak w poniższym przykładzie:
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)