
Ein Bericht über Sleirsgoevys Version der Exploit-Implementierung von CVE-2018-4386 von Fire30 namens Bad_Hoist
[!Hinweis] Hintergrundinformationen zur PS4:
Die PlayStation 4 Konsole verfügt über eine benutzerdefinierte AMD x86-64 CPU (8 Kerne). Ihr Orbis OS basiert auf FreeBSD (v9.0) mit Teilen von NetBSD. Sie enthält auch eine Vielzahl zusätzlicher Open-Source-Software, wie Mono VM und WebKit.
Der vom PS4 verwendete Internetbrowser wird tatsächlich mit dem Open-Source-WebKit-Projekt gebaut. Dies ist die Open-Source-Layout-Engine, die Webseiten in den Browsern für iOS, Wii U, 3DS, PS Vita und die PS4 rendert.
Der PS4 Internetbrowser besteht tatsächlich aus 2 separaten Prozessen. Derjenige, den wir für die Codeausführung kapern, ist der WebKit Core Process (der z.B. das Parsen von HTML und CSS, das Dekodieren von Bildern und das Ausführen von JavaScript übernimmt). Der andere kümmert sich um alles andere: Anzeige von Grafiken, Empfang von Controller-Eingaben, Verwaltung von Verlauf und Lesezeichen usw.
Der PS4 WebKit-Browser verwendet mehrere Heap-Allokatoren, die jeweils verschiedenen Komponenten dienen. Dies sind die folgenden:
Der Kern von CVE-2018-4386 ist ein logischer Fehler in der JavaScriptCore (JSC)-Engine von WebKit (v605.1.15), der Version, die in der PS4-Firmware 6.XX verwendet wird. Der Fehler befindet sich in der Funktion BytecodeGenerator::hoistSloppyModeFunctionIfNecessary und beinhaltet die unsachgemäße Behandlung von Variable Hoisting im Sloppy-Mode-JavaScript, insbesondere innerhalb von for-in-Schleifen.
Angreifbare Komponente (ForInContext):
Das, was wir primär anvisieren, ist ForInContext. Dies ist eine interne Struktur, die von JavaScriptCore verwendet wird, um den Zustand einer for-in-Schleife zu verwalten, die aktuelle Iterationsvariable und die Menge der enumerierten Eigenschaften zu verfolgen.
Wenn eine Funktionsdeklaration innerhalb einer for-in-Schleife hochgehoben wird, sollte die Engine das zugehörige ForInContext-Objekt invalidieren, wenn die Iterationsvariable überschrieben wird. Aufgrund des Fehlers tritt diese Invalidierung jedoch nicht ein. Dadurch kann die Iterationsvariable durch ein beliebiges Objekt ersetzt werden. Trotzdem behandelt die Engine die Variable weiterhin als Zeichenfolgen-Eigenschaftsnamen.
Wenn der Bytecode-Handler op_get_direct_pname später aufgerufen wird, verwendet er die Iterationsvariable direkt als String-Objekt, ohne Typprüfung.
Indem wir ein manipuliertes Objekt anstelle eines Strings übergeben, was zu einer Typverwirrung führt, können wir dies so ausnutzen, dass wir Speicherkorruption und sogar nützliche Exploit-Primitiven wie addrof, fakeobj und Arbiträres Lesen/Schreiben erreichen.
Structure-ID: Jedes Objekt in JavaScriptCore, einschließlich interner Darstellungen wie WTF::StringImpl, hat eine Structure-ID (oder einen Typ-Tag), die der Engine mitteilt, um welche Art von Objekt es sich handelt und wie seine Felder zu interpretieren sind.
Typverwirrung: Unser Exploit missbraucht den CVE-2018-4386-Fehler, um ein JavaScript-Objekt als StringImpl interpretieren zu lassen. Dies ist der Zweck der Funktion create_impl(), die ein typverwirrtes WTF::StringImpl-Objekt zurückgibt, das dann an die Funktion trigger() übergeben werden kann, als das willkürliche Objekt, über das wir bereits im Abschnitt Schwachstellenmechanismus dieses Write-ups gesprochen haben.
Damit dies funktioniert, müssen das Speicherlayout und die Structure-ID "nah genug" an dem sein, was die Engine für ein echtes String-Objekt erwartet.
JSString::toIdentifier() intern?Es gibt eine Methode in der WebKIT JavaScriptCore-Engine des PS4-Internetbrowsers mit dem Namen JSString::toIdentifier(). Diese Methode konvertiert ein JavaScript-String-Objekt (JSString) in eine interne Identifier-Darstellung.
Dieser Identifier wird in der gesamten Engine verwendet, um effizient Eigenschaftsnamen, Variablennamen und andere Zeichenfolgen zu vergleichen, zu speichern und nachzuschlagen, die von der JavaScript-Engine schnell und häufig referenziert werden müssen.
Es überprüft, ob das Objekt ein gültiger String ist und ob seine Structure-ID dem entspricht, was die Engine für ein String-Objekt erwartet. Wenn der String ein Rope (eine Verkettung von Strings) ist, kann er ihn vor der Konvertierung glätten. Anschließend ruft er entweder einen vorhandenen Identifier für den String ab oder erstellt einen neuen, falls dieser nicht existiert.
Dieser Identifier wird dann intern für schnelle Eigenschafts- und Variablennachschlage verwendet.
JSString::toIdentifier()-PrüfungenWenn der Exploit in die for-Schleife eintritt, die 1024 Mal iteriert, erstellt jede Iteration ein neues typverwirrtes WTF::StringImpl-Objekt mit 32 neuen Structure-IDs, die von der create_impl()-Funktion zurückgegeben werden. Wenn dieses typverwirrte Objekt verwendet und als willkürliches Objekt an trigger() übergeben wird, ruft JSC JSString::toIdentifier() darauf auf.
JSString::toIdentifier() überprüft bestimmte Bits in der Structure-ID, um zu bestätigen, dass das Objekt ein gültiger String ist oder als solcher behandelt werden kann. Indem viele Objekte mit verschiedenen Layouts und Structure-IDs erzeugt werden, erhöht der Exploit die Wahrscheinlichkeit, dass mindestens eines eine Structure-ID hat, die die internen Prüfungen in JSString::toIdentifier() besteht.