CSS Injection
Last updated
Last updated
Groupe de sécurité Try Hard
Les sélecteurs CSS sont conçus pour correspondre aux valeurs des attributs name
et value
d'un élément input
. Si la valeur de l'attribut de l'élément d'entrée commence par un caractère spécifique, une ressource externe prédéfinie est chargée :
Pour contourner cette limitation, vous pouvez cibler un élément frère ultérieur en utilisant le combinateur de frères général ~
. La règle CSS s'applique ensuite à tous les frères suivant l'élément d'entrée caché, ce qui permet de charger l'image d'arrière-plan :
Un exemple pratique d'exploitation de cette technique est détaillé dans l'extrait de code fourni. Vous pouvez le consulter ici.
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 créés.
Réévaluation du CSS : Vous devez avoir la capacité de cadrer la page, ce qui est nécessaire pour déclencher la réévaluation du CSS avec les charges utiles nouvellement générées.
Ressources externes : La technique suppose la possibilité d'utiliser des images hébergées à l'extérieur. Cela peut être limité par la politique de sécurité du contenu (CSP) du site.
Comme expliqué dans cet article, il est possible de combiner les sélecteurs :has
et :not
pour identifier le contenu même des é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 :
En combinant cela avec la technique @import suivante, il est possible d'exfiltrer beaucoup d'informations en utilisant l'injection CSS à partir de pages aveugles avec blind-css-exfiltration.
La technique précédente présente certains inconvénients, vérifiez les prérequis. Vous devez soit être capable d'envoyer plusieurs liens à la victime, soit être capable d'encapsuler la page vulnérable à l'injection CSS dans un iframe.
Cependant, il existe une autre technique astucieuse qui utilise CSS @import
pour améliorer la qualité de la technique.
Cela a été d'abord présenté par Pepe Vila et cela fonctionne comme suit :
Au lieu de charger la même page une fois et encore avec des dizaines de charges utiles différentes à chaque fois (comme dans la technique précédente), nous allons charger la page une seule fois et juste avec une importation vers le serveur des attaquants (c'est la charge utile à envoyer à la victime) :
L'import va recevoir un script CSS des attaquants et le navigateur va le charger.
La première partie du script CSS que l'attaquant enverra est un autre @import
vers le serveur des attaquants.
Le serveur des attaquants ne répondra pas encore à cette demande, car nous voulons divulguer certains caractères, puis répondre à cet import avec la charge utile pour divulguer 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'import demandé à l'étape 2.
La réponse sera 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 et ensuite l'avant-dernier.
L'attaquant va suivre cette boucle jusqu'à ce qu'il parvienne à divulguer 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.
Le script va essayer 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:
Cela permet au script de divulguer le secret plus rapidement.
Parfois, le script ne détecte pas correctement que le préfixe + suffixe découvert est déjà le drapeau complet et il continuera vers l'avant (dans le préfixe) et vers l'arrière (dans le suffixe) et à un moment donné, il restera bloqué. Pas de soucis, il suffit de vérifier la sortie car vous pouvez y voir le drapeau.
D'autres façons d'accéder aux parties du DOM avec les 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 compte rendu:
Référence: Attaque basée sur CSS : Abus de la plage unicode de @font-face, PoC XS-Search basé sur les erreurs par @terjanq
L'intention globale est de utiliser une police personnalisée à partir 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.
Utilisation de police personnalisée:
Une police personnalisée est définie en utilisant la règle @font-face
à l'intérieur d'une balise <style>
dans la section <head>
.
La police est nommée poc
et est récupérée à partir d'une adresse externe (http://attacker.com/?leak
).
La propriété unicode-range
est définie sur U+0041
, ciblant le caractère Unicode spécifique 'A'.
Élément Objet avec Texte de Secours:
Un élément <object>
avec l'id="poc0"
est créé dans la section <body>
. Cet élément tente de charger une ressource à partir de http://192.168.0.1/favicon.ico
.
La font-family
pour cet élément est définie sur 'poc'
, tel que 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.
La pseudo-classe :target
est utilisée pour sélectionner un élément ciblé par un fragment d'URL, tel que spécifié dans la spécification CSS Selectors Level 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 en matière de sécurité survient lorsque les attaquants exploitent la fonctionnalité de fragment Défilement vers le texte, 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 implique d'injecter une règle CSS comme suit:
Dans de tels scénarios, si le texte "Administrateur" 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é aux côtés d'un fragment de défilement vers le texte :
Voici, l'attaque manipule l'injection HTML pour transmettre le code CSS, visant le texte spécifique "Administrateur" à travers le fragment Scroll-to-text (#:~:text=Administrateur
). Si le texte est trouvé, la ressource indiquée est chargée, signalant involontairement sa présence à l'attaquant.
Pour atténuer, les points suivants doivent être notés :
Correspondance STTF Contrainte : 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 jetons arbitraires.
Restriction aux Contextes de Navigation de Niveau Supérieur : STTF fonctionne uniquement dans les 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 Utilisateur : STTF nécessite un geste d'activation de l'utilisateur pour fonctionner, ce qui signifie que les exploitations ne sont possibles que par le biais de navigations initiées par l'utilisateur. Cette exigence atténue considérablement le risque d'automatisation des attaques sans interaction utilisateur. Néanmoins, l'auteur de l'article de blog souligne des conditions et des contournements spécifiques (par exemple, l'ingénierie sociale, l'interaction avec des extensions de navigateur prédominantes) 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.
Vous pouvez spécifier des polices externes pour des valeurs unicode spécifiques qui ne seront collectées que si ces valeurs unicode sont présentes sur la page. Par exemple :
Référence: Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację
La technique décrite consiste à extraire du texte d'un nœud en exploitant les ligatures de police et en surveillant les changements de largeur. Le processus comprend plusieurs étapes :
Création de polices personnalisées :
Les polices SVG sont conçues avec des glyphes ayant un attribut horiz-adv-x
, qui définit une largeur importante 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 en utilisant fontforge.
Détection des changements de largeur :
Le CSS est utilisé pour s'assurer que le texte ne se coupe 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é :
Processus d'exploitation :
Étape 1 : Des polices sont créées pour des paires de caractères avec une largeur importante.
Étape 2 : Une astuce basée sur la barre de défilement est utilisée 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 : Après avoir détecté 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 l'astuce @import
en CSS, améliorant les performances de l'exploit.
Référence: PoC utilisant Comic Sans par @Cgvwzq & @Terjanq
Cette astuce a été publiée dans ce fil de discussion Slackers. Le jeu de caractères 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 étendre 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
Pendant cette transition, le tour de magie unicode-range est utilisé pour identifier chaque nouveau caractère au fur et à mesure qu'il rejoint le préfixe. Cela est réalisé en passant la police à 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 de détecter les caractères uniques au fur et à mesure de leur apparition, elle ne spécifie pas quel caractère est répété, seulement qu'une répétition s'est produite.
Essentiellement, l'unicode-range est utilisé pour détecter un caractère, mais comme nous ne voulons pas charger une police externe, nous devons trouver un autre moyen. Lorsque le caractère est trouvé, il est attribué à la police Comic Sans préinstallée, ce qui le rend plus grand et déclenche une barre de défilement qui va divulguer le caractère trouvé.
Vérifiez le code extrait du PoC :
Référence : Cela est mentionné comme une solution infructueuse dans ce compte rendu
Ce cas est très similaire au précédent, cependant, dans ce cas, l'objectif de rendre certains caractères plus grands que d'autres est de cacher quelque chose comme un bouton pour qu'il ne soit pas pressé par le bot ou une image qui ne se chargera pas. Ainsi, nous pourrions mesurer l'action (ou l'absence d'action) et savoir si un caractère spécifique est présent dans le texte.
Référence : Cela est mentionné comme une solution infructueuse dans ce compte rendu
Dans ce cas, nous pourrions essayer de vérifier si un caractère est dans le texte en chargeant une fausse police depuis la même origine :
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 en l'absence de cache, il y a un mécanisme de réponse 304 non modifiée, donc la réponse devrait être plus rapide que d'autres éléments.
Cependant, si la différence de temps entre la réponse mise en cache et celle non mise en cache n'est pas assez 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.
Référence : Cela est mentionné comme une solution infructueuse dans cet article
Dans ce cas, vous pouvez indiquer au CSS de charger des centaines de fausses polices depuis la même origine lorsqu'une correspondance se produit. De cette manière, vous pouvez mesurer le temps nécessaire et déterminer si un caractère apparaît ou non avec quelque chose comme :
Et le code du bot ressemble à ceci :
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 indicateur pour déterminer s'il y a une correspondance de police.
Groupe de sécurité Try Hard