 Das ist Jonathan J. from the MSRC in Israel, a Division of Microsoft, and the stage is yours and that is your course. Guten Morgen, mein Name ist Jonathan, und ich bin ein Studio-Researcher in MSRC in Israel. All my free time I play CTFs with Team Perfect Blue, and I also do research on my free time. Ich spiele CTF, und ich bin 18, und ich habe letztes Jahr mit Sicherheit angefangen. Und jetzt erzähle ich euch, was ich über das letzte Jahr gelernt habe, und wenn ihr lernen wollt, was ich da rausbekommen habe, dann könnte das für euch hilfreich sein. Für die Erfahrenerin ist der zweite Teil, wo ich ein Zero-Day in Chakra gefunden habe. Und wenn ihr auch gerade erst anfängt, dann reicht das wahrscheinlich schon, um hier mit zu kommen. Und am Schluss werde ich mit dem Modus einigen, hoffentlich funktioniert die auch. Also, das ist Anfang. Warum machen wir solche Forschung? Verbundbarkeiten sind für mich Puzzle. Wir müssen irgendwelche Fehler finden, die der Entwickler nicht gefunden hat. Und ich fand das ganz toll. Es gibt verschiedene Definitionen. Auf Wikipedia schaut, dann sieben mal, es gibt mehrere Definitionen. Manche sind komisch, die Wahrscheinlichkeit, dass ein ... Ich weiß nicht genau, was das meint. Wenn ich mich Fehler im Programm sehe, wenn ich sehe, dass mir das erlaubt, den Gedanken oder den erwarteten Programm plus zu finden, aber da es eigentlich noch nicht entwinden soll. Also, als ich angefangen habe, hatte ich ein bisschen Erfahrung und Programmierung. Und ich war ganz gut. Ich habe ein bisschen C, C++, Assemblersprache, Betriebssystem, und ich wusste ein bisschen Python. Ich habe das Buch, die C-Programmiersprache. Und das gibt dir alles C-Wissen, was du brauchst, um die Wunderung, die ich vorher schon einzusteigen. Das nächste, was ich gemacht habe, ist, ich habe online gelegt. Ich habe online über klassische Stackoverflows gelesen, Integeroverflows gelesen und so weiter. Und dann habe ich versucht, mein Wissen anzuwenden. Und da habe ich an Wargames enttage genommen. Die sind offline. Man muss irgendeine Frachtele finden und die ausnutzen. Am Anfang habe ich nicht so viele herausgekriegt. Aber ich habe dann hinterher die Lösung gelesen und da habe ich das ausgelernen. Das nächste, was ich gemacht habe, ist, ich habe bei Capture the Flag mitgemacht. Und das sind Wettbewerbe. Man muss gegen andere Teams teilnehmen. Man muss mit seinen Freunden spielen. Da habe ich meine Kollegen, meine Teamkollegen, getroffen. Manchmal funktioniert es nicht, aber manchmal funktioniert es richtig gut. Wir sind um die ganze Welt gereist. Und dann waren wir bei den Finals. Da haben wir das bezahlt bekommen. Wir haben auch ein bisschen was von der Welt gesehen. Das war toll. Und ich glaube, die Capture the Flag Wettbewerbe sind eine gute Art, um die Sicherheit zu lernen. Danach bin ich ins tiefe Wasser gesprochen. Also wenn man die Anfänge gelernt hat, muss man sich den schwereren Sachen aussetzen. Und selbst wenn man sich das noch nicht zutraut und am Anfang hat es nicht funktioniert. Am Anfang habe ich es immer verloren. Aber irgendwann habe ich es dann geschafft. Und ich denke, es ist wichtig, dass man sich nicht fürchtet, das auch anzugehen. Es ist ein tolles Tweet von LiveOverflow. Das finde ich toll. Da steht drin, was ich glaube. Man muss so schnell wie möglich von den einfachen Sachen weggehen und zu den schweren Sachen gehen, die man nicht verstehen. Das hilft dir, Dinge zu verstehen, von denen du dachtest, dass du das verstehst, aber eigentlich nicht tust. Man muss über Disziplinen hinweggehen. Und das gibt an einem tiefe Ausverständnis. LiveOverflow hat einen sehr guten Channel. Den schaue ich auch. Ich empfehle euch, die Videos zu schauen. Nachdem ich das erreicht hatte, habe ich geübt. Ich habe viel geübt. Ich habe also solche Herausforderungen alleine angenommen. Und da lernt man dann auch die Tricks, die man braucht, um diese Herausforderungen anzugehen. Einige von denen haben Muster da drin. Und wenn man die Muster ein paar Mal sieht, ein guter Weg, um diese Muster zu kennenzulernen, ist, viele Herausforderungen anzunehmen. Und das ist, warum ich auch real-world, also echte Strachstellen habe, versucht anzugreifen. Es gibt eine gute Verbindung zwischen die Capture the Flag und der echten Welt. Die Probleme, die sind sowohl in Capture the Flag als auch im echten Leben. Man kann es auch, wenn man es versucht, in der echten Welt, in der echten Welt. Man kann es auch, wenn man es versucht, in der echten Welt, in der echten Welt, in der echten Welt, in der echten Welt, in der echten Welt, in der echten Welt. Das Hauptproblem, das man hat, wenn man echte Forschung macht, ist, dass der Code so groß ist, aber man sollte sich nicht fürchten, einfach zu suchen. Man kann versuchen, Dinge zu lösen, selbst wenn es anfangs eine sitzige Nivelle ist. Nachdem ich ein bisschen geübt habe, habe ich versucht, eine Vulnerabilität zu finden. Da habe ich festgestellt, dass ich Schwachsteilenforschung ist, Fehler zu finden. Wir wollen die finden und das passiert, indem man ein Code auditiert. Das kommt mit der Übung. Sobald man das verstanden hat und beherrscht, ich glaube, die Übung ist sehr wichtig. Wie findet man Schwachsteilen? Wir haben Muster drin. Muster sind etwas, das man mit der Zeit lernt. Ich habe das nicht so neuer gemacht. Wie habe ich das gemacht, wenn ich es nur ein Jahr lang mache? Ja, durch die Übung. Übung kann die Zeit abdecken. Und die Schwachsteilen haben Muster drin. Programmierfehler wie Integer-Oberfehler, Vorzeichenfehler, Menschen machen Fehler und Menschen machen Fehler. Ein schönes Beispiel ist das hier. Auf der dritten Zeile haben wir einen Overflow, den Entwickler kennen. Aber die machen trotzdem diesen Fehler. Wir sind menschlich. Diese Fehler existieren und die existieren nicht nur im Capture the Flag. Man kann einfacher finden. Es ist ein großer Unterschied zwischen Capture the Flag und echtem CTF. Man weiß nicht, was man damit machen muss. Manchmal weiß ich, wie ich es ausbauen kann. Man kann Funktions-Pointer, Funktions-Pointer, Funktions-Pointer überschreiben. Meistens, wenn man es im Capture the Flag sieht, dann weiß man, was man damit tun muss. In der echten Welt hat man einige Grundlagen oder grundlegende Fehler und die muss man in der Kette zusammenfügen um dann später auszunutzen. Das, was ich in Chaka gemacht habe, da habe ich mehrere hintereinander gefügt. Das war alles, was ich über Schwachstellen und Forschung weiß. Also, machen wir dann weiter mit JavaScript. Ich habe ganz gesagt, dass JavaScript gelernt hat, ich habe es wirklich nicht gelernt, aber es ist einfach so, wenn man ein paar Programmiersprachen gesehen hat, dann ist das Lernen von so Sprachen mit JavaScript sehr ähnlich, ziemlich einfach. Ja, was machen JavaScript? Engines? Wir müssen den Code verstehen, den JavaScript Entwickler schreiben. Da sind einige Teile drin. Für uns ist der wichtigste Teil der JIT Compiler. Es geht für Adjust-in-Time-Compiler, also Atom-Kompilierung. Was es macht, ist, dass es die JavaScript-Funktion nimmt und die zu nativen Maschinencode kompiliert, um die Performance zu verbessern. Der JIT Compiler ist auch dafür verantwortlich, Optimierung zu machen. Der macht durchaus sehr viele Annahmen über den Code und manchmal können diese Annahmen falsch sein. Wir sehen uns nachher an, wie das dann raussehen kann. Aber fangen wir erst mal mit dem Basics an. JavaScript ist eine dynamisch-dukosette Sprache, wo es eigentlich ziemlich lesbar ist. Man kann Arrays machen auf verschiedene Arten und Weisen. Man kann Arrays mit verschiedenen Arten von Daten und M-Mann haben. Außerdem hat JavaScript Prototypen. Das ist im Prinzip so was, wie man Features von anderen Objekten erben kann. Wenn das Kindobjekt von einem älteren Objekt erzeugt wurde, erbt das Kindobjekt einige der Eigenschaften von dem älteren Objekt. Dieser Eigenschaft ist für die Sicherheitslücke, die ich gefunden habe, sehr wichtig. In dem Fall sieht man dann, wie man da auf dem Kompilieren sieht. Man kann auch auf dem Kompilieren sehen, wie man da auf dem Prototypen zugehefen kann mit unseren Prototoprojectiven. Dann gibt es auch noch Prozies. Prozies sind Objekte, die andere Objekte rappen können, um passen zu können. Und dann einige von den Operationen, die das gerappte Objekt implementiert, um definieren zu können. Hier wollen wir zum Beispiel, dass X 0, X 1, der 3, 7 ist. Aber dadurch, dass der Exzentler überall schrieben wird, an diesem Fall wird tatsächlich Godproxy da ausgerufen. Also, JavaScript hat auch noch Arrays. Chakra hat zum Beispiel Arrays mit Typen. Der erste Typ, über den ich speichern möchte, ist JavaScript Native Interay. Und das ist ein Array, das integer beinhaltet, die 4 bytes lang sind. Und ja, es ist ein Konzip einfach integer. JavaScript hat auch ein natives Float Array, was Floats beinhaltet. Und typischerweise sind diese Floats tatsächlich 8 bytes lang. Und dann gibt es noch JavaScript Arrays, die Objekte beinhalten, also letztendlich Pointer. Und die sind auch 8 bytes pro Element groß. Also schauen wir uns jetzt mal an, wie wir zwischen den Typen konvertieren können. Wir fangen an mit einem Array von integer und konvertieren das dann in ein Float Array, indem wir einen Float-Member dorthin zufügen. Und dann konvertieren wir das Ganze nochmal in ein JavaScript Array. Also es ist jeweils Seiteneffekte davon, dass man das Material hinter setzt. Das heißt, wenn wir dann sowohl Floats als Objekte in einem einzelnen Array, dann wird das dann ein einfaches JavaScript Array. Und ja, eine etwas komische Anordnung für diese ganze Sache ist dann sowas, was wir hier sehen. Und man sieht das nicht typischerweise, aber das ist ganz wichtig für diesen Talk, denn wenn man zwei Arrays hat und man das ein Array als Prototyp von dem anderen assignt, dann wird das rechte Array automatisch auch wieder zu einem JavaScript Array. Und diese Konvertierung passiert genau zu dem Zeitpunkt, wo dieser Wert zugewiesen wird. Wir schauen uns mal an, wie dieser Array tatsächlich ein Speicher aussehen. Also wenn wir ein JavaScript Array haben, dann hat es einige Flex, die Eigenschaften von dem Array angeben, die Länge und den Head. Der Head ist ein Cointer auf ein sogenanntes Segment und ein Segment ist dann eine Zusammenhängung der Speicherbereich der Elemente beinhaltet. Also einige Elemente von dem Array sind da drin und das Segment beinhaltet auch noch ein Pointer zum nächsten Segment. Das heißt, im Prinzip ist das alles eine verketterte Liste über Pointer verkettert von den einzelnen Segmenten, die dann das gesamte JavaScript Array ausmachen. Wir haben das Array auch noch an. Also wir haben jetzt ein zweilanges Array mit Integer an drin, 0x3, 1x3, 0x7. Und wir sehen das dann im Speicher aus. Wir haben die JavaScript Array Eigenschaften, also das ist nicht in Rot markiert, das Array Flex fällt zum Beispiel. Und dann haben wir in Grün das tatsächlich Segment und wir sehen wieder hier Länge und Größe und in Blau dann tatsächlich das memory-Layout von dem Segment. Und da sind genau die beiden Elemente drin, die wir definiert haben. Also, was ist in diesem Array Flex eigentlich drin? Gesagt, das sind Flags, die eigene Eigenschaften von dem Array kundieren. Und das ist als ehemaliger definiert. Und interessanterweise gibt es da dieses HasNoMissingValues-Flag. Und wenn man sieht, dass es HasNoMissingValues ist, dann sieht man in unserem Beispiel von eben, dass dieses InitialArray-Value bei uns genau aus diesen beiden Flags bestand, ObjectArrayFlexStag und HasNoMissingValuesStag. Das erste ist jetzt nicht so wichtig für unseren Zweck, aber das zweite schon. Das bedeutet, dass das Array keine Löcher hat, also Hall. Was bedeutet das? Das bedeutet, dass es sein kann, dass ein Array vielleicht Elemente Willow 2 belegt hat, aber dass seine Mitte da nicht. Und wie das im Speicherer präsentiert wird, sieht dann so aus, wie auf der Folie hier gezeigt. Und wie ihr sehen könnt, hat dieses Array ein Loch und das Array Flexfeld hat auch dieses HasNoMissingValues on. Und das macht eigentlich ... Aber wenn wir uns das Memory-Layout, also das Speicher-Layout, da veranschauen, dann sieht das komisch aus. Wir haben da Detriefe und Verwandte. In der Mitte haben wir eine magische Konstante, Nullif, SSF, 8, 0 und so weiter. Und jetzt könnte man sich überlegen, ob das jetzt irgendwie ein Loch repräsentieren soll oder sowas in dem Array. Aber wir haben ja eigentlich schon diese Informationen, nämlich die HasNoMissingValues-Flex. Und das bedeutet, dass ... Ja, anscheinend auch irgendwie eine zweite Variante verwendet wird, um ein Loch in dem Array zu repräsentieren. Und das ist wirklich komisch, das provoziert Fragen. Denn wir haben hier im Prinzip zwei Sachen, die eigentlich immer dasselbe repräsentieren sollten. Wir haben das Slack von dem Array. Und den Inhalt von dem Array, den wir gerade eben gesehen haben, das FFF, 8, bla bla bla. Und das heißt, wenn ... Was passiert, wenn wir jetzt nicht übereinstimmen? Was passiert, wenn wir das irgendwie auf die Reihe kriegen, diese Session herzustellen? Und das sind dann wieder einen Konsistenz einfügen. Auch ... Wir vermischen ja auch da eine Metadaten an der Stelle. Also das heißt, wenn diese Konstante in einem Kontrollfluss verwendet werden, dann können wir das eventuell verwenden, wenn wir die Konstante an der Stelle beeinflussen können. Was ist das für eine Frage, wenn wir also irgendwie diese MissingValue, also diesen fehlenden Wert an der Stelle fängt? Dafür gab es schon eine Sicherheitswacke. Die Milch, was die gemacht haben, ist die Konstante, in einer Floater-Array, ranzutun. Der Wert war vorher nicht der, diese manche Werte, den wir gerade gesehen haben, sondern eine, weil die der Floater vorhin zahlen. Und ... Dann wurde das auf ... Ja, mit ein paar Maßnahmen ... Ja, wurde dagegen gearbeitet. Aber ... Wir können uns noch überlegen, wie man diesen komischen Zustand in eine Sicherheitswacke ... ändern kann. Vorher wollten wir über was Interessantes reden. Und ... ... der Break, den die beiden gefunden haben. Sieht so aus, die JavaScript Arrays, die speichern Floats nicht erst, also Floats, sondern sie boxen sie zuerst. Die Xoren, sie mit dieser Konstante hier. Bevor man den Wert in das Array reinschreibt, würde er halt damit die Xort. Können wir denn ... ... fehlende Werte in so einem JavaScript Array haben? So, dass die Konstante geändert ist. Wir sehen also hier das Xort. Wir sehen alte Werte, und können daraus neu machen. Die ... ... die JavaScript Engine, die sollte diese Konstante nicht verändern. Sonst würde das nicht funktionieren. Es sieht so aus, als ob die Konstante sich nicht ändert. Oh, das heißt so, wir können ... ... die Konstante nicht verändern. Oh, das heißt so, wir können die ... ... wir können die Konstante boxen, mit dem FFF. Und das gibt uns die Möglichkeit, den ursprünglichen Konstantenwert reinzuschreiben. Wenn wir also ein Xort von drei Elementen haben, und zwei Stück, die gleich sind, dann kippen wir wieder so ein Array. Das ist das, was wir haben. Wenn wir so ein Array sind, dann kippen wir wieder so den Ursprungswert. Wenn ich zwei habe, mit dem F-Wert und ... ... und den Magic-Wert haben will, dann kann ich diesen Magic-Wert genau auf den Weg erzeugen. Und das ist die ... ... das ist die Schwachstelle, die ich gefunden habe. Wir haben ... ... eine rudimentäre Ausverständnis von JavaScriptmaschinen. Und ... ... diese Idee oder dieses Verständnis, dass da ... ... Boxing passiert und dass sie versucht haben, damit sich vor dieser Vulnerabilität zu schützen, das hat wohl nicht funktioniert. Also wir machen hier ein JavaScript-Array draus und kein Flotarray draus. Also wie können wir diesen komischen Zustand in eine Schwachstelle überführen? Das erste, was wir verstehen müssen, ist, wie sieht so eine Schwachstelle aus? Just in Time-Compiler sind ... ... Fehler sind meistens Type-Verwechslungen. Das Programm denkt ... ... etwas als ein Typ und es ist aber tatsächlich von einem anderen Typ. Die häufigsten sind Nebeneffekte. Das sind Dinge, die ... ... in Maschinencode generiert wird, der generiert wird aus dem JIT-Compiler. Wenn der die ... ... häufig genutzte Funktion kompliziert. Wir haben also irgendeine Funktion, zum Beispiel FOO, und die endet den Typ von einem Array. Und die Funktion, die ... ... kompiliert worden ist, weiß nicht, dass das passiert ist und arbeitet so weiter als wäre es der Alte. Und das führt zu ... ... Typverwechslungen. Das erste, was wir machen, wenn wir so eine Schwachstelle haben, ist, wir nehmen ... ... wir machen das so, dass die Funktion in Maschinencode übersetzt wird. Das machen wir indem wir so einfach häufig aufrufen. Das nächste, was wichtig ist, der JIT-Compiler hat viele Annahmen. Er macht Annahmen über Typen und Dinge, die passieren und Dinge werden dem Aufruf gegeben sein werden. Er denkt, dass FOO nichts macht und deswegen denkt, dass man da auch nichts prüfen muss. Das heißt, er braucht auch hinterher nicht prüfen und das würde ja alles viel langsamer machen. Das hat also viele Annahmen, um Performance schneller zu machen. Sobald wir das gemacht haben und etwas haben, was die Annahme kaputt macht, dann können wir in komische Zustände kommen, wo wir die Schwachstelle ausnisten können. Wir rufen diesmal die Funktion noch mal auf, nachdem wir sie jetzt in Maschinencode übersetzt haben. Und jetzt rufen wir sie mit einem Array auf. Und die Funktion erwartet das natürlich nicht, dass da jetzt was anderes reinkommt. Und der Compiler denkt, es hat sich nichts geändert, aber wir haben etwas geändert. Die JIT-Compiler-Bugs sind sehr komplex. Die JIT-Compiler-Bugs sind sehr komplex. Häufig so. Wir haben den JIT-Compiler da in die Erde geführt, dass er nicht weiß, was passiert. Also, wir haben den Javascript-Array umgewandelt, aber er weiß es halt einfach nicht. Und dann geht es halt... Also, wir haben den Javascript-Array umgewandelt, aber er weiß es halt einfach nicht. Und dann geht es halt... Und dann geht es halt... Das sind JIT-Type-Rexzonen. Wir haben eine Funktion, um das Ding heiß zu machen. Das heißt, dass es kompliziert wird. Dann haben wir etwas, was... Was den Typ ändert. Und dann rufen wir die Funktion noch mal auf. Und darin haben wir eine Funktion, die Nebeneffekte durchführt. Jetzt kommen wir zu meiner Schwachstelle. Also, wir hatten einen Flag, was gezeigt hat, dass es keine fehlenden Werte gibt. Und wir hatten den Array-Inhalt. Wir haben es also jetzt geschafft, einen fehlenden Wert zu faken. Und Lockiehart und Sorry My Bad rufen diese Konkertfunktion auf. Die verlässt sich darauf, dass die Konkertfunktion auf die Konkertfunktion verlässt sich darauf, dass das MissingValues stimmt und dass der Inhalt stimmt. Und dadurch können wir in diesen komischen Zustand kommen. Warum haben wir das MissingValues-Flag und den Inhalt des Arrays etwas anderes anzeigen lassen? Lockiehart und Sorry My Bad haben also diese beiden Dinge desynchronisiert. Wir haben also jetzt einen Fake Array hergestellt und wir nennen es Buggy. Und das hat einen fehlenden Wert drin. Und das Flag, dass da fehlende Werte drin sind, setzten wir, dass es noch keine fehlenden Werte gibt, oder dass es auch trockene Werte gibt. Also, das hier ist der Code. Es ist nicht sehr schwer, es ist nur viel Code. Zuerst kommen wir auf zu dieser Funktion hier. Und die Funktion, die ist KonkertArgs und A-Item ist der Wert, auf den man es konzentrieren. Und wir müssen unten schauen, schauen, ob ein Statement rein kommt. Diese Funktion checkt, dass nur ein Segment in dem Array ist. Wir schauen, dass der Punkte zum nächsten Segment 0 ist und wir prüfen auch, dass die Länge von dem Array gleich der Länge des Segmentes ist. Jetzt checkt es auch noch, dass er noch ein bisschen Values flaggt. Und das können wir faken und das können wir umgehen. Und indem wir das machen, können wir diese Funktion falsch zurückkehren lassen und dann können wir in das If-Statement rein kommen. Jetzt wollen wir in das L-Statement rein, wo unten ein Copy-Array-Element aufgerufen wird. Und das nimmt P-Item-Array als Argument. Und das ist eine interne Funktion und die tut folgendes. Dieser Teil ist sehr interessant für uns. Das erste, was wir machen ist, die machen aus dem Array ein Enumerator und der läuft über jedes Element und jedes Mal den Zähler erhöhen. Wir lassen uns gucken, wie dieser Enumerator implementiert ist. Hier ist der Code für das MoveNext Funktion. Und wenn da hinten der Index fehlt, dann überspringen wir ihn. Das heißt, dass es jedes Mal, wenn er in dem Weihlug drin war und ein fehlender Wert war, hat er es übersprungen. Und das heißt also, der Zähler ist nicht gleich den Wert im Array, weil jedes Mal, wenn wir einen fehlenden Wert finden, dann wird der Counter nicht hochgezählt. Und dann können wir unten in dieses Statement rein und da wird Internal Fill von Prototypen aufgerufen. Das ist auch eine interessante Funktion. Das erste, was wir machen ist, sie geht durch alle Prototypen, durch die Kette von Prototypen. Der Prototyp ist ein Objekt, was wir geerbt haben. Das heißt also, wir haben eine Kette von Prototypen, weil der von dem war erben, der kann auch schon geerbt haben. Und dann ruft er hier diese langen Funktionsnamen auf mit diesem Prototypen auf. Der Prototyp wird direkt in ein JavaScript-Array umgewandelt. Es sollte wissen, dass der Prototyp ein JavaScript-Array ist und da durchschleifen. Der Prototyp kommt hier rein als Objektargument und wird zu einem Unsafe-Native-Array umgewandelt. Es prüft halt, dass es nicht von einem Native-Type ist, sondern dass es ein JavaScript-Array ist. Lass mich doch mal zusammenfassen. Wir haben Concat in ein JavaScript-Array umzuwandeln und nichts, was diese Umwandlung zeigt, anzeigt. Wir haben also jetzt diesen fehlenden Wert und die ganze Prototyp-Chain wird in einen JavaScript-Array umgewandelt. Das sind keine Native-Types. Das heißt, man sollte da nicht irgendwelche Zahlen reintun können, weil es ein JavaScript-Array sein sollte. Jetzt erinnert euch an Proxy. Proxy kann das einwickeln. Es macht Spaß, dass wir das zumachen können. Wir können die Funktionalität von Get-Prototype umdefinieren. Jedes Mal, wenn wir Get-Prototype aufrufen, dann definieren wir einen Verhalten. Erinnert euch an die Kette von Prototypen. Wir haben also diese Prototypen-Kette umgewandelt und haben uns damit erlaubt, eine beliebige Funktion aufzurufen. Der Get-Compiler überprüft, ob diese Funktion das Nebeneffekt hat ja oder nein. Und wenn ja, dann wird die ganze Funktion vom Get-Compiler so markiert. Wir wollen aber nicht, dass der Get-Compiler das mitkriegt. Wir wollen eine Typenverwechslung haben. Das heißt, wir nehmen eine existierende Funktion, z.B. Value auf, und die hat keine Seiteneffekte. Und dieser Trick erlaubt uns, ein beliebiges Objekt in der Prototypen-Kette den gewünschten Prototypen zurückzugeben. Das Erste, was wir machen, ist, wir gehen durch diesen ersten Schleife um die Funktion kompilieren zu lassen. Das nächste, was wir machen, ist, wir definieren zwei Bill-Arrays. Das Erste ist, da faken wir einen fehlenden Wert. Und das Zweite ist, das Ziel für die Typenverwechslung. So, das ist ein ganz normales Array. Das hat keinen Fehler. Wir definieren die Funktion von Get-Prototype auf. Dadurch, dass wir das umdefinieren, wenn diese Funktion aufgerufen wird, auf dem Array, dann haben wir die Implementierung umdefiniert, dass wir Array selber kriegen. Wenn wir jetzt ein Proxy definieren, dann haben wir diesen Get-Prototype aufgerufen, dann haben wir diesen Get-Prototype aufgerufen. Der Ergebniswert ist RRR. Da kommt ein Flotarray raus. Das erlaubt uns, einen native Flotarray zu haben. Obwohl die nicht in der Prototypenverwechslung sind, dann haben wir den Flotarray aufgerufen. Wir haben den Flotarray zu haben, obwohl die nicht in der Prototypenkette sein sollten. Jetzt gehen wir her, dass wir diesen fehlenden Wert neu definieren. Und jetzt haben wir das Missing-Value-Flag immer noch gesetzt auf var. Und wir haben aber den Wert eingefügt. Jetzt rufen wir die Get-Funktion nochmal auf. Das ist der wichtige Teil, wenn man diese Funktion aufruft. Hier oben, dieser Code wird aufgerufen. Wir definieren ein temperäres Array. Und dann setzen wir das erste Element. Und das erste Element von einem Array ist auf dem Float. Und es tut weiss, wenn die Umwandlung passiert, dass es ein JavaScript Float Array ist. Jetzt rufen wir die Funktion auf. Und wir geben ihr Buggy. Dadurch geht er durch die gesamte Prototypen-Chain. Und einer ist der Proxy. Und wenn wir der Proxy für den Proxy aufrufen, dann kriegen wir das R. Und jetzt haben wir das R. Aus dem Proxy rausgeholt. Und das R. Ist jetzt ein JavaScript-Array, weil dieser Loop durchgeführt wurde. Und am Ende von dieser Get-Funktion schreiben wir ein Wert in das Array rein. Und schreiben einen R. Und das R. Und schreiben einen Float in ein Array rein. Was ein JavaScript-Array ist. Das ist eine Prototypen-Kette. Und wir haben Pointer überschrieben. Mit einer Fließkommission. Und da haben wir 1, 2, 3, 4 reingeschrieben. Und am Schluss rufen wir da dieses Lockout. Und dann bleibt es ein Crash. Das ist der Proof-of-Concept-Code. Wir haben zuerst die Funktion heiß gemacht. Dann ist das Maschinencode geworden. Das Nächstes haben wir das Verhalten der GetPrototype-Funktion umdefiniert. Und haben er erlaubt, ein beliebiges Objekt zurückzugeben, wenn man das raufruft. Dann haben wir einen fehlenden Wert vorgetauscht. Und haben die GetFunktion aufgerufen. Und haben das in einem JavaScript-Array gemacht. Obwohl einer davon in einem Array... In der Prototypen-Kette ist halt das Alte drin. Und jetzt können wir die letzte Zeile von diesem Code erlauben uns, eine Zahl als ein Pointer reinzuschreiben. Und an der Stelle passiert genau die Typeverwechslung. Wir haben die Typenverwechslung zwischen dem Float und dem Pointer. Weil in der JIT die Umwandlung durchgeführt wurde. Also, wir kommen jetzt von einem Facebook-Konzert zur Code Institution. Wir haben jetzt eben hier ein sogenanntes fake-Object-Primitives. Also ein gefälsches Objekt gemacht. In unserem Fall haben wir diese Adresse 0x1234 gefaked. Aber wir können tatsächlich jedes beliebige Objekt im Rahmen faken. Und in unserem Beispiel ein Data-View-Objekt, was Pointer enthält, von dem man lesen und schreiben kann. Und das ist eben ein sogenanntes Read-Right-Primitives, weil sein Leser schreibt primitiv, mit dem wir ein Video gestellen im Arbeitsspeicher schreiben können. Und was man jetzt dafür machen kann, das ein bisschen einfacher zu machen, das ist ein ziemlich cooler Library, die da sehr viele Sachen einfach macht. Wir müssen da ein paar Sachen anpacken. Also, man gibt ihm ein Read-Right-Primitive, das wir uns gerade eben ausgeworfen haben. Und von da an, wängt dann ein Porn-Project sein, den Stack zu überschreiben, mit Hilfe dieses Read-Right-Primitives. Und dann kann man im Prinzip einfach Rob-Attack machen, und wir können oriental Programming attacken. Und, ja, was haben wir jetzt gemacht? Wenn wir uns unseren eigenen Code anschauen, dann haben wir den erstmal... also, als wir unseren eigenen Code angeschaut haben, dann haben wir den erstmal in der Sandbox ausgeführt. Aber da können wir natürlich dann keinen... also, nicht wirklich gut demonstrieren, dass wir jetzt wirklich Code-Ausführungen haben. Wir haben das Ganze dann nochmal unter Dienungs gemacht. Und, ja, da haben wir dann also auch wieder den Stack überschrieben, und konnten einen return-oriented Programming machen. Und, ja, das ist dann quasi genau der Schritt, wie man vom Proof-of-Concept tatsächlich den Code ausführung kommt. Dafür machen wir jetzt eine Demo, hoffen wir mal, dass das Ganze auch funktioniert. Ein Moment. So, let's hope everything works. So, basically, das... Wir haben Chakra-Corcom-Palfo, und da haben wir diesen Chakra-Corc für Dienungs kompiliert. Und... Jetzt haben wir so ein... ...Vertalie, der wir dann einen exploit geben und, ja, stelle euch drauf auf, dass das jetzt alles sehr schnell geht, weil Chakra sehr schnell ist und super Optimierung drin hat. Also, ja, das geht jetzt alles sehr schnell. Ja, jetzt haben wir hier eine Shell. Also, damit zu beweisen, dass wir tatsächlich Code-Ausführungen erreicht haben, führen wir mal den Taschenrechner aus. Das ist ja das klassische Beispiel. Und wir sehen, dass wir den Taschenrechner hier haben. And everything works as expected. So, a few things about... Let's get back to the talk. Gehen wir mal wieder zurück zum Vortrag. Wait. Sorry. So, was haben wir jetzt hier gesehen? Wir hatten... The demo shows us a very simple thing. Wir hatten im Prinzip eine sehr einfache Situation. Wir hatten das Proof-of-Konzept. Dann haben wir den JIT Compiler dazu gebracht, einen Seiteneffekt zu übergehen, um ausgenutztes JIT Compiler, den nicht versteht, nämlich genau, dass es möglich ist, das Float- oder Editor-Array in einen JavaScript-Array zu konvertieren. Und das haben wir dann ausgenutzt, um einen Read-Write-Primitiv zusammenzubauen, mit dem wir dann um return-oriented Power-Bringing machen konnten, um dann beliebige Code-Ausführungen zu erreichen. Ich hoffe, mein Vortrag war hilfreich für alle, die mit sich jetzt vorhin schon anfangen wollen. Und ansonsten lustig für alle, die sich damit schon ein bisschen besser auskennen. Diesseits werden verfügbar gemacht. Ich danke euch allen, dass ihr hier wart. Und ich weiß, dass sehr viele andere interessante Vorträge da waren. Danke, dass ihr da wart. War das dein erster Vortrag? War das der erste Vortrag, den du vor so einem großen Publikum gehalten hast? War ein sehr guter Vortrag. Wir haben zwei Mikrofone. Wenn ihr Fragen habt, dann stellt euch dahin. Eine vom Internet? Eine Frage vom Internet. Danke für den super Talk. Es hat mich gewundert, dass der JavaScript-Engine für Microsoft Edge open-source ist. Ist das etwas, wo sich Microsoft generell hin bewegt? Mehr open-source? Also, der JavaScript-Engine ist open-source, aber ich weiß nicht, wie die Zukunft davon aussehen wird. Hi, danke für deinen sehr interessanten Talk. Wie viel Vorwissen hattest du, als du angefangen hast, dich damit zu beschäftigen? Wie viel Vorwissen bezüglich JavaScript-Compilers und dynamischen Sprach-Runtimes und so weiter? Wie lange musstest du sich damit beschäftigen, bevor du anfangen konntest, nach Sicherheit und Zusammenarbeit? Wie lange musstest du damit beschäftigen, bevor du anfangen konntest? Wie lange musstest du damit beschäftigen, bevor du anfangen konntest, nach Sicherheit und Zusammenarbeit? Wie lange musstest du anfangen konntest, nach Sicherheit und Zusammenarbeit? Was ich gemacht habe, was ich angefangen habe, ich habe viele Fehlerberichte gelesen für Chakra. Ich habe mich alle aber die meisten gelesen und habe versucht zu verstehen, was sie tun und warum sie existieren. Und das hat mich dazu geführt, mein eigenes Fehler zu suchen. Ich habe grob verstanden, wie JavaScript-Engines funktionieren und dann habe ich Chakra angeschaut und habe nach speziellen davon gesucht. Du hast erwähnt, dass die Prozesse Windows in einer Sandbox laufen und das heißt, du warst nicht in der Lage, den Taschenrechner zu starten. Würde das den exploit da draußen wirklich stoppen oder gäbe es dann immer noch Möglichkeiten, da auszubrechen? Also um beliebigen Code auszuführen, muss man aus der Sandbox raus. Man kann ein paar Sachen mit der Sandbox machen, aber die sind eingeschränkt. Ich habe keine Möglichkeit gefunden, aus der Sandbox rauszubrechen. Vielleicht finde ich irgendwann einen. Da sind viele, viele Mitigationen, viele Vorkehrungen dagegen, dass so was funktioniert. Ohne Sandboxausbruch kann man nicht wirklich interessante Sachen machen, aber man kann trotzdem ein paar Sachen machen. Wie viel Zeit hast du darauf verwendet? Ich habe an Chakra von Juli vor zwei Monaten etwas über JavaScript gewusst. Das Wichtigste für mich waren die Beispiele. Nicht so sehr. Zeit damit zu verbringen. Das meiste kommt aus Übung und meine Übung war halt, viel Forschung zu lesen und die internen Details über Chakra zu lesen. Vielleicht von Mai oder zwei Monaten davor. Damit verabschieden sich dann auch aus der