CSS Injection
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Selektory CSS są tworzone, aby dopasować wartości atrybutów name
i value
elementu input
. Jeśli atrybut wartości elementu wejściowego zaczyna się od określonego znaku, ładowany jest zdefiniowany zewnętrzny zasób:
Jednakże, to podejście napotyka ograniczenie w przypadku ukrytych elementów wejściowych (type="hidden"
), ponieważ ukryte elementy nie ładują tła.
Aby obejść to ograniczenie, możesz celować w następny element rodzeństwa, używając kombinatora rodzeństwa ogólnego ~
. Reguła CSS następnie stosuje się do wszystkich rodzeństw następujących po ukrytym elemencie wejściowym, powodując załadowanie obrazu tła:
A practical example of exploiting this technique is detailed in the provided code snippet. You can view it here.
Aby technika CSS Injection była skuteczna, muszą być spełnione określone warunki:
Długość ładunku: Wektor wstrzyknięcia CSS musi obsługiwać wystarczająco długie ładunki, aby pomieścić skonstruowane selektory.
Ponowna ocena CSS: Powinieneś mieć możliwość osadzenia strony, co jest konieczne do wywołania ponownej oceny CSS z nowo wygenerowanymi ładunkami.
Zasoby zewnętrzne: Technika zakłada możliwość korzystania z obrazów hostowanych zewnętrznie. Może to być ograniczone przez Politykę Bezpieczeństwa Treści (CSP) witryny.
Jak wyjaśniono w tym poście, możliwe jest połączenie selektorów :has
i :not
w celu identyfikacji treści nawet z elementów niewidocznych. Jest to bardzo przydatne, gdy nie masz pojęcia, co znajduje się na stronie ładującej wstrzyknięcie CSS.
Możliwe jest również użycie tych selektorów do wyodrębnienia informacji z kilku bloków tego samego typu, jak w:
Łącząc to z następującą techniką @import, możliwe jest wyeksfiltrowanie dużej ilości informacji za pomocą wstrzykiwania CSS z niewidocznych stron przy użyciu blind-css-exfiltration.
Poprzednia technika ma pewne wady, sprawdź wymagania wstępne. Musisz być w stanie wysłać wiele linków do ofiary, lub musisz być w stanie iframe'ować stronę podatną na wstrzykiwanie CSS.
Jednak istnieje inna sprytna technika, która wykorzystuje CSS @import
, aby poprawić jakość techniki.
Zostało to po raz pierwszy pokazane przez Pepe Vila i działa to w ten sposób:
Zamiast ładować tę samą stronę raz za razem z dziesiątkami różnych ładunków za każdym razem (jak w poprzedniej), zamierzamy załadować stronę tylko raz i tylko z importem do serwera atakującego (to jest ładunek do wysłania do ofiary):
Import będzie otrzymywał jakiś skrypt CSS od atakujących, a przeglądarka go załaduje.
Pierwsza część skryptu CSS, którą wyśle atakujący, to kolejny @import
do serwera atakujących.
Serwer atakujących nie odpowie na to żądanie jeszcze, ponieważ chcemy wycieknąć kilka znaków, a następnie odpowiedzieć na ten import ładunkiem, aby wycieknąć następne.
Druga i większa część ładunku będzie ładunkiem wycieku selektora atrybutu
To wyśle do serwera atakujących pierwszy znak sekretu i ostatni.
Gdy serwer atakujących otrzyma pierwszy i ostatni znak sekretu, odpowie na import żądany w kroku 2.
Odpowiedź będzie dokładnie taka sama jak w krokach 2, 3 i 4, ale tym razem spróbuje znaleźć drugi znak sekretu, a następnie przedostatni.
Atakujący będzie podążał za tą pętlą, aż uda mu się całkowicie wycieknąć sekret.
Możesz znaleźć oryginalny kod Pepe Vili do wykorzystania tego tutaj lub możesz znaleźć prawie ten sam kod, ale skomentowany tutaj.
Skrypt spróbuje odkryć 2 znaki za każdym razem (od początku i od końca), ponieważ selektor atrybutu pozwala na robienie rzeczy takich jak:
To pozwala skryptowi na szybsze wycieknięcie sekretu.
Czasami skrypt nie wykrywa poprawnie, że odkryty prefiks + sufiks to już pełna flaga i będzie kontynuował do przodu (w prefiksie) i do tyłu (w sufiksie), a w pewnym momencie się zawiesi. Nie martw się, po prostu sprawdź wyjście, ponieważ możesz tam zobaczyć flagę.
Inne sposoby dostępu do części DOM za pomocą sektorów CSS:
.class-to-search:nth-child(2)
: To wyszuka drugi element z klasą "class-to-search" w DOM.
:empty
selektor: Używany na przykład w tym opisie:
Referencja: Atak oparty na CSS: Wykorzystywanie unicode-range w @font-face, PoC XS-Search oparty na błędach autorstwa @terjanq
Ogólnym zamiarem jest użycie niestandardowej czcionki z kontrolowanego punktu końcowego i zapewnienie, że tekst (w tym przypadku 'A') jest wyświetlany tą czcionką tylko wtedy, gdy określony zasób (favicon.ico
) nie może być załadowany.
Użycie niestandardowej czcionki:
Niestandardowa czcionka jest definiowana za pomocą reguły @font-face
w tagu <style>
w sekcji <head>
.
Czcionka nazywa się poc
i jest pobierana z zewnętrznego punktu końcowego (http://attacker.com/?leak
).
Właściwość unicode-range
jest ustawiona na U+0041
, celując w konkretny znak Unicode 'A'.
Element Object z tekstem zapasowym:
Element <object>
z id="poc0"
jest tworzony w sekcji <body>
. Element ten próbuje załadować zasób z http://192.168.0.1/favicon.ico
.
font-family
dla tego elementu jest ustawiona na 'poc'
, zgodnie z definicją w sekcji <style>
.
Jeśli zasób (favicon.ico
) nie uda się załadować, zawartość zapasowa (litera 'A') wewnątrz tagu <object>
jest wyświetlana.
Zawartość zapasowa ('A') będzie renderowana przy użyciu niestandardowej czcionki poc
, jeśli zewnętrzny zasób nie może być załadowany.
Pseudo-klasa :target
jest używana do wybierania elementu, który jest celowany przez fragment URL, jak określono w specyfikacji CSS Selectors Level 4. Ważne jest, aby zrozumieć, że ::target-text
nie pasuje do żadnych elementów, chyba że tekst jest wyraźnie celowany przez fragment.
Pojawia się problem bezpieczeństwa, gdy atakujący wykorzystują funkcję Scroll-to-text fragment, co pozwala im potwierdzić obecność konkretnego tekstu na stronie internetowej, ładując zasób z ich serwera poprzez wstrzyknięcie HTML. Metoda polega na wstrzyknięciu reguły CSS, takiej jak ta:
W takich scenariuszach, jeśli tekst "Administrator" jest obecny na stronie, zasób target.png
jest żądany z serwera, co wskazuje na obecność tekstu. Przykład tego ataku można wykonać za pomocą specjalnie przygotowanego URL, który osadza wstrzyknięty CSS obok fragmentu Scroll-to-text:
Here, atak manipuluje wstrzyknięciem HTML, aby przesłać kod CSS, celując w konkretny tekst "Administrator" za pomocą fragmentu Scroll-to-text (#:~:text=Administrator
). Jeśli tekst zostanie znaleziony, wskazany zasób jest ładowany, nieumyślnie sygnalizując swoją obecność atakującemu.
Aby złagodzić ryzyko, należy zwrócić uwagę na następujące punkty:
Ograniczone dopasowanie STTF: Fragment Scroll-to-text (STTF) jest zaprojektowany do dopasowywania tylko słów lub zdań, co ogranicza jego zdolność do wycieków dowolnych sekretów lub tokenów.
Ograniczenie do kontekstów przeglądania na najwyższym poziomie: STTF działa wyłącznie w kontekstach przeglądania na najwyższym poziomie i nie funkcjonuje w ramach iframe, co sprawia, że wszelkie próby wykorzystania są bardziej zauważalne dla użytkownika.
Konieczność aktywacji przez użytkownika: STTF wymaga gestu aktywacji przez użytkownika do działania, co oznacza, że wykorzystania są możliwe tylko poprzez nawigacje inicjowane przez użytkownika. Wymóg ten znacznie zmniejsza ryzyko automatyzacji ataków bez interakcji użytkownika. Niemniej jednak autor wpisu na blogu wskazuje na konkretne warunki i obejścia (np. inżynieria społeczna, interakcja z powszechnymi rozszerzeniami przeglądarki), które mogą ułatwić automatyzację ataku.
Świadomość tych mechanizmów i potencjalnych luk jest kluczowa dla utrzymania bezpieczeństwa w sieci i ochrony przed takimi taktykami eksploatacyjnymi.
Aby uzyskać więcej informacji, sprawdź oryginalny raport: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/
Możesz sprawdzić eksploitację wykorzystującą tę technikę dla CTF tutaj.
Możesz określić zewnętrzne czcionki dla konkretnych wartości unicode, które będą zbierane tylko wtedy, gdy te wartości unicode są obecne na stronie. Na przykład:
When you access this page, Chrome and Firefox fetch "?A" and "?B" because text node of sensitive-information contains "A" and "B" characters. But Chrome and Firefox do not fetch "?C" because it does not contain "C". This means that we have been able to read "A" and "B".
Reference: Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację
Technika opisana polega na ekstrakcji tekstu z węzła poprzez wykorzystanie ligatur czcionek i monitorowanie zmian w szerokości. Proces składa się z kilku kroków:
Tworzenie niestandardowych czcionek:
Czcionki SVG są tworzone z glifami mającymi atrybut horiz-adv-x
, który ustawia dużą szerokość dla glifu reprezentującego sekwencję dwóch znaków.
Przykład glifu SVG: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>
, gdzie "XY" oznacza sekwencję dwóch znaków.
Te czcionki są następnie konwertowane do formatu woff za pomocą fontforge.
Wykrywanie zmian szerokości:
CSS jest używane, aby zapewnić, że tekst nie zawija się (white-space: nowrap
) i aby dostosować styl paska przewijania.
Pojawienie się poziomego paska przewijania, stylizowanego w sposób odmienny, działa jako wskaźnik (oracle), że w tekście obecna jest określona ligatura, a tym samym określona sekwencja znaków.
Użyty CSS:
Proces eksploatacji:
Krok 1: Tworzone są czcionki dla par znaków o znacznej szerokości.
Krok 2: Wykorzystywana jest sztuczka oparta na pasku przewijania, aby wykryć, kiedy renderowany jest duży glif (ligatura dla pary znaków), co wskazuje na obecność sekwencji znaków.
Krok 3: Po wykryciu ligatury generowane są nowe glify reprezentujące sekwencje trzech znaków, włączając wykrytą parę i dodając znak poprzedzający lub następujący.
Krok 4: Wykrywanie ligatury trzech znaków jest przeprowadzane.
Krok 5: Proces powtarza się, stopniowo ujawniając cały tekst.
Optymalizacja:
Obecna metoda inicjalizacji używająca <meta refresh=...
nie jest optymalna.
Bardziej efektywne podejście mogłoby obejmować sztuczkę CSS @import
, poprawiając wydajność eksploatu.
Reference: PoC using Comic Sans by @Cgvwzq & @Terjanq
Ta sztuczka została opublikowana w tym wątku Slackers. Zestaw znaków użyty w węźle tekstowym może być wyciekany za pomocą domyślnych czcionek zainstalowanych w przeglądarce: nie są potrzebne zewnętrzne - ani niestandardowe - czcionki.
Koncepcja opiera się na wykorzystaniu animacji do stopniowego rozszerzania szerokości div
, pozwalając jednemu znakowi na przejście z części 'sufiksowej' tekstu do części 'prefiksowej'. Proces ten skutecznie dzieli tekst na dwie sekcje:
Prefiks: Początkowa linia.
Sufiks: Kolejna linia(y).
Etapy przejścia znaków będą wyglądać następująco:
C ADB
CA DB
CAD B
CADB
Podczas tego przejścia wykorzystywana jest sztuczka unicode-range do identyfikacji każdego nowego znaku, gdy dołącza do prefiksu. Osiąga się to poprzez zmianę czcionki na Comic Sans, która jest zauważalnie wyższa niż domyślna czcionka, co w konsekwencji wywołuje pojawienie się paska przewijania w pionie. Pojawienie się tego paska przewijania pośrednio ujawnia obecność nowego znaku w prefiksie.
Chociaż ta metoda pozwala na wykrywanie unikalnych znaków w miarę ich pojawiania się, nie określa, który znak jest powtarzany, tylko że wystąpiło powtórzenie.
W zasadzie, unicode-range jest używane do wykrywania znaku, ale ponieważ nie chcemy ładować zewnętrznej czcionki, musimy znaleźć inny sposób. Gdy znak jest znaleziony, otrzymuje wstępnie zainstalowaną czcionkę Comic Sans, która powiększa znak i wywołuje pasek przewijania, który ujawnia znaleziony znak.
Check the code extracted from the PoC:
Referencja: To jest wspomniane jako nieudane rozwiązanie w tym opisie
Ten przypadek jest bardzo podobny do poprzedniego, jednak w tym przypadku celem powiększenia konkretnych znaków w porównaniu do innych jest ukrycie czegoś takiego jak przycisk, aby nie został naciśnięty przez bota lub obraz, który nie zostanie załadowany. Możemy więc zmierzyć akcję (lub brak akcji) i wiedzieć, czy konkretny znak jest obecny w tekście.
Referencja: To jest wspomniane jako nieudane rozwiązanie w tym opisie
W tym przypadku możemy spróbować wyciekować, czy znak znajduje się w tekście, ładując fałszywą czcionkę z tego samego źródła:
Jeśli występuje dopasowanie, czcionka zostanie załadowana z /static/bootstrap.min.css?q=1
. Chociaż nie załaduje się pomyślnie, przeglądarka powinna ją zbuforować, a nawet jeśli nie ma bufora, istnieje mechanizm 304 not modified, więc odpowiedź powinna być szybsza niż inne rzeczy.
Jednakże, jeśli różnica czasowa między zbuforowaną odpowiedzią a niezbuforowaną nie jest wystarczająco duża, nie będzie to przydatne. Na przykład autor wspomniał: Jednak po testach odkryłem, że pierwszym problemem jest to, że prędkość nie różni się zbytnio, a drugim problemem jest to, że bot używa flagi disk-cache-size=1
, co jest naprawdę przemyślane.
Referencja: To jest wspomniane jako nieudane rozwiązanie w tym opisie
W tym przypadku możesz wskazać CSS do załadowania setek fałszywych czcionek z tego samego źródła, gdy wystąpi dopasowanie. W ten sposób możesz zmierzyć czas, jaki zajmuje, i dowiedzieć się, czy znak się pojawia, czy nie, za pomocą czegoś takiego jak:
A kod bota wygląda tak:
Więc, jeśli czcionka się nie zgadza, czas odpowiedzi podczas odwiedzania bota powinien wynosić około 30 sekund. Jednak jeśli czcionka się zgadza, zostanie wysłanych wiele żądań w celu pobrania czcionki, co spowoduje ciągłą aktywność w sieci. W rezultacie zajmie to więcej czasu, aby spełnić warunek zatrzymania i otrzymać odpowiedź. Dlatego czas odpowiedzi można wykorzystać jako wskaźnik do określenia, czy czcionka się zgadza.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)