Hallo nochmal! Morgen beginnen wir den Unterricht in einer neuen Gruppe im Kurs
"Reverse Engineering" . Traditionell teilen wir mit Ihnen die Übersetzung von nützlichem Material zum Thema. Lass uns gehen!
Für einige Angreifer ist es wichtig, dass der Exploit äußerst zuverlässig ist. Es sollte immer zur Codeausführung führen, wenn es auf einem System mit einer bekannten Plattform und Version von Flash gestartet wird. Um es zu erstellen, können Sie besonders hochwertige Fehler verwenden. Dieser Artikel beschreibt die Verwendung eines dieser Fehler sowie Faktoren, die ihn für einen zuverlässigen Betrieb besonders geeignet machen.
FehlerCVE-2015-3077 - Das Problem der
Typverwirrung in den Filtersetzern Adobe Flash
Button und
MovieClip , mit dem Sie jeden
Filtertyp mit jedem anderen verwechseln können. Ich habe es Anfang Dezember 2015 gemeldet und im Mai wurde es behoben. Der Fehler tritt auf, weil der Cracker den Konstruktor überschreiben kann, der zum Initialisieren des Filterobjekts verwendet wird. Der Beispielcode, der das Problem reproduziert, ist unten dargestellt:

Dieser Code ist aufgrund der Verwendung des Operators [], der für die Kompilierung in Flash CS erforderlich ist, etwas verwirrend. Der logisch äquivalente Code (der nicht kompiliert wird) ist unten angegeben:

Dieser Code setzt das Filterfeld des Objekts: Button oder MovieClip auf BlurFilter, das dann direkt in Flash gespeichert wird. Der BlurFilter-Konstruktor wird dann vom ConvolutionFilter-Konstruktor überschrieben. Danach wird der Getter aufgerufen und ein ActionScript-Objekt erstellt, um den ursprünglichen BlurFilter zu speichern. Der Konstruktor wurde jedoch bereits überschrieben, sodass ConvolutionFilter aufgerufen wird. Dies erzeugt ein Objekt vom Typ ConvolutionFilter, das durch die Rückgabe des ursprünglichen BlueFilter unterstützt wird.
Letztendlich kann auf ConvolutionFilter-Felder zugegriffen werden (Lesen und Schreiben), als gehörten sie zu BlurFilter. Ähnliches gilt für alle anderen Filtertypen. Dies eröffnet eine breite Palette von Manipulationen, die zum Ausnutzen nützlich sind.
Das folgende Diagramm zeigt die Position der ursprünglichen Objekte im Speicher, die möglicherweise durch diese Sicherheitsanfälligkeit unter 64-Bit-Linux verwirrt werden könnten.

In zwei Fällen sind Zeiger mit Ganzzahlen und Gleitkommazahlen vergleichbar, die manipuliert werden können. Dies bedeutet, dass Zeiger direkt gelesen und geschrieben werden können. Da die Felder der Objekte gemäß der Definition der Klasse nach Größe geordnet und sortiert sind, befinden sie sich immer an vorhersehbaren Stellen, damit das Schreiben und Lesen nicht fehlschlägt. Diese Eigenschaften sind wichtig, um die Zuverlässigkeit des Exploits sicherzustellen.
AusnutzenDa das Ausnutzen dieses Problems das wiederholte Ausführen von
Typverwirrung erfordert, habe ich zunächst eine Dienstprogrammfunktion für
Typverwirrung erstellt ,
FilterConfuse.confuse . Es räumt auch auf: Es versetzt die ActionScript-Filterkonstruktoren in ihren normalen Zustand zurück, um wiederholt eine anfällige Funktion aufzurufen, ohne das Verhalten von ActionScript außerhalb der Funktion selbst zu beeinträchtigen.
Der erste Schritt bestand darin, ASLR zu umgehen, indem die Adresse der virtuellen Funktionstabelle definiert wurde (kurz vtable). Der ideale Weg, dies zu tun, besteht darin, ein Objekt mit einer vtable mit einem Objekt zu verwechseln, in dem sich ein Element mit der vtable überlappt, das manipuliert werden kann. Die vtable aller Filterobjekte hat jedoch den gleichen Versatz. Stattdessen habe ich das
BitmapData-Objekt im DisplacementMapFilter verwendet, um die vtable-Adresse zu bestimmen.
Um die Position im BitmapData-Speicher des Objekts zu bestimmen, habe ich DisplacementMapFilter mit BevelFilter verwechselt. Dadurch wurde der in DisplacementMapFilter gespeicherte BitmapData-Zeiger an den BevelFilter-Farbeigenschaften (
shadowColor ,
shadowAlpha ,
HighlightColor und
HighlightAlpha ) ausgerichtet. Diese Eigenschaften werden von zwei 32-Bit-Ganzzahlen (oben und unten als Farbe und Farbe dargestellt) unterstützt, und die Farbeigenschaften greifen auf 24 Bit jeder Ganzzahl zu, während die Alpha-Eigenschaften auf die oberen 8 Bit zugreifen. Wenn Sie diese Eigenschaften lesen und mit Bitarithmetik kombinieren, können Sie die unmittelbare BitmapData-Adresse des Objekts extrahieren.

Anschließend müssen Sie die vtable oben im BitmapData-Objekt lesen. Dafür habe ich die
Matrixeigenschaft des ConvolutionFilter-Objekts verwendet. Es wird als Zeiger auf ein Array von Gleitkommazahlen gespeichert, unter denen beim Festlegen der Eigenschaft Speicher zugewiesen wird, und ein ActionScript-Array mit diesen Zahlen wird zurückgegeben, wenn die Eigenschaft empfangen wird. Durch Setzen des Matrixzeigers auf ein BitmapData-Objekt können Sie den Inhalt dieses Objekts als Array von Gleitkommazahlen aus dem Speicher lesen.
Um den Zeiger zu setzen, habe ich das ConvolutionFilter-Objekt mit dem DisplacementMapFilter-Objekt verwechselt (nicht der oben verwendete DisplacementMapFilter!) Und die Position der BitmapData des Objekts oben in der
mapPoint- Eigenschaft festgelegt. Die mapPoint-Eigenschaft ist ein Punkt mit ganzzahligen Koordinaten x und y (p_x und p_y in der folgenden Abbildung), die dem Matrixzeiger in ConvolutionFilter entsprechen, wodurch das Festlegen dieses Werts vereinfacht wurde. Danach wurde es möglich, die vtable aus dem BitmapData-Objekt mithilfe eines Matrix-Arrays aus dem ConvolutionFilter-Objekt zu lesen (es ist erwähnenswert, dass das Objekt dazu mit DisplacementBitmapFilter verwechselt und dann wieder mit ConvolutionFilter verwechselt werden musste).

An diesem Punkt wird es aufgrund der Verwendung von Gleitkommazahlen schwieriger, die Zuverlässigkeit des Exploits aufrechtzuerhalten. Die Werte vtable_low und vtable_high werden aus der ConvolutionFilter-Matrix als Gleitkommazahlen gelesen, da dies ein Array-Typ ist. Leider ist nicht jeder gültige Zeigerwert eine gültige Gleitkommazahl. Dies bedeutet, dass das Lesen des Werts NaN oder, schlimmer noch, einen nicht ganz korrekten numerischen Wert zurückgibt.
Um dieses Problem zu lösen, müssen Sie im Idealfall über einen Getter auf vtable_low und vtable_high zugreifen, der sie als Ganzzahlen interpretiert. Dies liegt jedoch nicht daran, dass Filterelemente aufgrund ihrer Funktionalität normalerweise schweben.
Glücklicherweise ist die virtuelle AS2-Maschine faul genug, um Gleitkommazahlen zu interpretieren. Sie konvertiert einen Wert nur dann in einen Gleitkommawert, wenn eine Operation in ActionScript ausgeführt wird. Ursprüngliche Operationen erfordern normalerweise keine Interpretation, außer für spezielle Operationen wie Arithmetik. Dies bedeutet, dass beim Kopieren einer Gleitkommazahl von einem Matrixarray nach vtable_low oder vtable_high der Wert im Speicher beibehalten wird, auch wenn er für float ungültig ist, während die Variable, in die er kopiert wurde, in ActionScript oder zum Ausführen von arithmetischen Operationen im nativen System nicht verwendet wird Code. Wenn also der Wert einer Variablen sofort mit einem anderen Typ verwechselt wird, der den gesamten Bereich von 32-Bit-Werten unterstützt, z. B. int, entspricht er garantiert dem ursprünglichen Wert im Speicher des Matrix-Arrays. Um Unzuverlässigkeit beim Exploit zu vermeiden, ist es daher wichtig, vor dem Bearbeiten von Floats in ActionScript eine Typverwirrung durchzuführen.
Zu diesem
Zweck habe ich eine Konvertierungsklasse,
FloatConverter , geschrieben, die
Typverwirrung in Filtern verwendet, um Funktionen von Integer zu Float und Float zu Integer zu implementieren. Es verwechselt die
Matrix- ColorMatrixFilter-Eigenschaft (verwechseln Sie sie nicht mit der ConvolutionFilter-Matrixeigenschaft), bei der es sich um eine Reihe integrierter Floats handelt, mit den GlowFilter-Eigenschaften
color und
alpha , die auf verschiedene int-Bytes zugreifen.

Auf diese Weise können Sie eine zuverlässige Konvertierung eines Floats in ein Int implementieren, dies funktioniert jedoch leider nicht zuverlässig in die entgegengesetzte Richtung. Um auf das Farbarray in ColorMatrix in ActionScript zuzugreifen, wird das gesamte Array kopiert, auch wenn Sie nur auf das erste zugreifen. Beim Kopieren eines Arrays wird jedes Element in Number konvertiert, was einen Aufruf von Zeigern enthält (z. B. das Aufrufen des valueOf eines Objekts). Da das Farbarray das längste der gesamten GlowFilter-Klasse ist, wird es bei Verwechslung mit dem GlowFilter gehäuft. Dies bedeutet, dass möglicherweise unbekannte Werte aus diesem Heap konvertiert werden, was zum Absturz führen kann, wenn sie bei der Konvertierung in Number auf ungültige Zeiger verweisen. Daher habe ich für int-to-float einen Float-Konverter mit einem anderen verwirrenden ConvolutionFilter und DisplacementMapFilter implementiert, der eine direkte Umwandlung ist und keine unbekannten Werte aus dem Heap aufruft.

Dies löst das Problem von Abstürzen, die durch den Zugriff auf unbekannte Werte vom Heap verursacht werden. Leider gibt es ein weiteres Zuverlässigkeitsproblem, das mit Floats in diesem Exploit verbunden ist. Dies liegt an der Implementierung des ConvolutionFilter-Matrix-Getters. Alle numerischen Werte in ActionScript 2 sind vom Typ Number, dh die Vereinigung einer Ganzzahl und eines Zeigers zu einer doppelten Zahl. Die ursprüngliche ConvolutionFilter-Matrix wird als Array von Gleitkommazahlen gespeichert, jedoch in das ActionScript-Array kopiert, um den Zugriff beim Aufruf des Matrix-Getters zu erhalten, und die Werte werden dabei in double konvertiert. Wenn Sie dann den Gleitkommakonverter aufrufen, werden sie wieder in Gleitkommazahlen konvertiert.
Das Umwandeln einer Gleitkommazahl in eine Zahl mit doppelter Genauigkeit und umgekehrt speichert normalerweise ihren Wert, jedoch nicht, wenn der Gleitkommawert SNaN ist. Gemäß der Gleitkomma-Spezifikation gibt es zwei Arten von NaNs: Silent NaN (QNaN) und Signal NaN (SNaN). Wenn QNaN angezeigt wird, geschieht nichts, aber SNaN löst in einigen Fällen eine Gleitkomma-Ausnahme aus. In x86 führt die Konvertierung von double in float immer zu QNaN (auch wenn double von SNaN stammt), um unerwartete Ausnahmen zu vermeiden.
Wenn daher die unteren Bits des Zeigers SNaN sind, wird er in QNaN konvertiert, was bedeutet, dass das erste Bit (das erste Mantissenbit, Bit 22) gesetzt wird, wenn es nicht sollte. Dieses Problem kann beim Lesen von vtable vermieden werden - das dritte Byte des Zeigers, der das erste Bit enthält, kann ohne Ausrichtung gelesen werden, um den aktuellen Wert zu bestätigen. Der Code wird also ohne Alignments gelesen (nach erneutem Lesen der vtable mit um eins erhöhtem Bitmap-Zeiger) und der int-Wert angepasst, wenn sich herausstellt, dass der Float SNaN ist.
Mit den oben beschriebenen Float-Konvertern kann die vtable-Adresse in eine Ganzzahl konvertiert werden. Jetzt müssen Sie den Code erhalten, um ihn mit dieser Adresse auszuführen. Eine einfache Möglichkeit, den Anweisungszeiger zu verschieben, besteht darin, die vtable des Objekts (oder einen Zeiger auf ein Objekt mit einer vtable) zu überschreiben. Dies kann durch Verwechseln des ConvolutionFilter-Matrixarrays und der BitmapData des DisplacementFilter-Zeigers erfolgen.
Das Ende des ersten Teils. Der zweite Teil der Übersetzung wird etwas später veröffentlicht. Jetzt warten wir auf Ihre Kommentare und laden alle zum OTUS-
Reverse-Engineering- Kurs ein.