 So, der nächste Vortrag, der ist Treff, okay, also KTRW, Single-Flight, Hardware, Debugging ist nicht wirklich möglich mit iPhones und daher ist Sicherheitsforschung mit dem Kern auch echt eine Herausforderung. Aber mit dem Apple-Apple-E10-Chip hat Apple jetzt spezielle Speicherregionen definiert. Und Brandon hat innerhalb dem Google Project Zero ein debattable, also ein debattbares iPhone erschaffen. Und wenn wir das jetzt erklären, hier das alles geschafft hat, mit einem herkömmlichen iPhone. Einen großen Applaus für unseren Vortragmen. Super, ich hoffe hier zu sein, dass ihr jetzt mit dem Talk gekommen seid. Heute zeige ich euch, wie ich jetzt was erlangt habe, was ich schon lange wollte, nämlich ein debattbares iPhone. Also, was meine ich damit eigentlich genau? Also, um euch ein bisschen Kontext zu geben, damit ihr das versteht, dann erkläre ich erstmal, was das nicht so häufig erklärt wird. Und das ist eine Entschuldigung hier für die Audio-Störung. Also, es gibt eben verschiedene Debug-Schnittstellen, um mit Embedded-Geräten Debugging betreiben zu können. Und die erlauben einem dann zum Beispiel in einzelne Instruktionsschritten durch den Bootloader durchgehen zu können, Registerinhalte auszugeben, zu modifizieren. Und das ist zum Beispiel für Apple-Ingenieure total wichtig zu haben. Aber Apple möchte das auf keinen Fall an produktiven iPhones, also die, die dann an die Massen rausgegeben und verkauft werden, drin haben. So, was man braucht, um eben meinen Ansatz hier durchzuziehen, ist ein spezielles Kabel. Das nennt man normalerweise Probe. Man sieht hier etwas, das Kansi-Kabel heißt und es hat einen speziellen Lightning-Verbindung an einem Ende. Und das hat eine spezielle ID fest eingebrannt, die es gegenüber dem Telefon als Debug-Gerät identifiziert. Es hat da noch einen speziellen Controller in der Mitte, der es als Debug-Gerät ermöglicht und dann eben den ganz normalen USB-Anschluss. Auf dem Laptop lässt man dann normalerweise Software laufen. Das ist ganz normal, das findet man online, die hier heißt Astris. Das ist keine Software, die Apple freiwillig rausgibt, sondern die ist, glaube ich, gelegt. Also das ist definitiv nichts, was jetzt von Apple offiziell genehmigt wurde. Aber es gibt eben Leute, die an dieses Software rankommen und dann mit diesen Debug-Kabeln, diese Debug-Kabeln nutzen können zusammen mit der Software. Mit dem Telefon zu reden. Und hier sehen wir dann zum Beispiel ein Debug-Gerät, das an einem 32-bit iPhone verbunden ist und man sieht hier Register-Inhalte. Man kann ja ganz viel Low-Level-Debugging-Arbeit machen. Also was ich jetzt sagen muss, ist, dass ich keine Dev-Ust-Dev-Ust bedeutet. Also ich möchte da keinen Zugriff drauf haben, ich habe da auch keinen Zugriff drauf in meiner regulären Arbeit. Aber ich möchte an dieser Stelle nochmal betonen, dass es total nützlich wäre, wenn wir solche Low-Level-Debug-Schnittstellen einfach verfügbar halten. Und das war eben genau die Motivation für mein Projekt. Ich möchte einen normalen iPhone-Gerät, das im Laden kaufen kann, eben eine Debug-Möglichkeit geben, die equivalent zu dem ist, was wir eben gesehen haben. Ein sogenanntes Home-Broad-Entwicklungstelefon. Es gibt ja da eben verschiedene Sachen, die ich auf jeden Fall machen möchte. Ich möchte Kernelspeicher patchen. Ich möchte vor allem auch den Ausführbahnspeicher im Kernel patchen. Das heißt, ich möchte Instruktionen modifizieren, Shale-Code einfügen. Ich möchte die normalen Debugger-Feature zu haben, also Breakpoints, Watchpoints etc. Und das dritte, was ich wollte, ist, dass ich so was machen konnte, dass ich einfach mit ganz normalen Debuggern arbeiten könnte. Also, die man auch sonst zur Arbeit verwendet. Also, ich wollte keinen proprietären Software wie Astris oder so was, der nur Apple zugänglich ist eigentlich, um damit zu interagieren. Ich wollte Standard-Debugger haben. Und dann wollte ich, dass man die Software auf dem Gerät trotzdem updaten kann. Also, ich wollte eine so tiefgreifende Sicherheitslücke finden, dass es auch über Updates nutzbar bleibt. Und nicht, dass Apple das direkt wegpatched nach einem Softwareupdate. Also, ich möchte auch immer die newesten Version debuggen können. Ja, das wäre auf jeden Fall ziemlich nützlich, weil ich dann zum Beispiel die Unterschiede zwischen einzelnen iOS-Versionen anschauen kann. Aber ja, ich möchte eben, also letztendlich möchte ich einfach die Entwicklungskosten amortisieren, indem man lange Zugriff auf das iOS-Betriebs-Team hat. Und ja, in der Praxis bedeutet das, dass ich eine Lücke im Bootloader brauche oder irgendeine Art Hardware-Bug. Also, irgendwas, das total schwierig zu patchen ist oder wenn es patchbar ist, dass es so früh im Bootprozess ist, dass es möglich, dass es dann immer noch möglich wäre, den iOS-Kernel zu updaten. Und das letzte, was ich wollte, war, dass ich mit diesem Entwicklungstelefon nur, also, dass ich für diesen ganzen Prozess nur Teile brauche, die man im ganz normalen Apple Store kaufen kann. Also, wenn ich mich an den CPUs, in denen die Entwicklungs-Fuses noch rausgelötet sind oder so, irgendwelche Spezien, lieber Kabel, das wollte ich alles nicht. Also, es gab etwas Wichtiges heute, was passiert ist und dass ich, und das war einige Tage vor ich das Open-Sourcen wollte, gab es ein Bootrom-Exploit zwischen dem für alle iPhones, von dem 4S bis zum iPhone X. Und dieser Exploit ist stärker als das, was ich selber entwickelt habe. Also, alles, was ich in meinem Telefon machen kann, ist natürlich möglich mit dem, aber ich möchte euch einfach zeigen, dass es halt Annahmen gibt, die ich ursprünglich hatte, dass diese halt einfach nicht mehr gültig sind nach diesem Exploit oder nach der Veröffentlichung dieses Exploits. Und damit möchte ich jetzt über KTTRR sprechen. Und das Ganze ist halt nicht einfach zu machen. Es gibt halt eine Ausweichmaßnahme namens KTTRR. Und die erste Sache auf dieser Liste, die ich, das erste Feature, das ich haben wollte, also die erste Fähigkeit von meinem Programm wollte ich haben, war, den Kernelspeicher zu patchen. Das heißt, ich musste den Code, den Binärencode überschreiben können und auch ausführen können. Und Apple hat das halt verhindern wollen. Es gibt halt ein Kernelcache im Speicher, der dann auch von dem Secure Bootprozess beschützt wird, aber sobald das System läuft, versucht Apple halt den Kernelcache abzusichern, soweit es halt irgendwie geht, so dass es halt nicht möglich ist, Sachen im Kernelcache zu verändern. Und so will Apple halt sicherstellen, dass Kernelcode, der einmal gestartet ist, halt nicht mehr verändert wird nachträglich. Aber es gibt auch einige Bereiche, die halt nicht unbedingt schreibbar sein müssen. Und aber es gibt auch einige Datenstücke, die für andere Zwecke benötigt werden. Verschiedene Tabellen für die Adressen und diese zusätzlichen Daten werden sollen halt nicht veränderbar sein. Und KTR sichert diese Speicherbereiche, damit man sie nicht manipulieren kann. Und soweit wir es wissen, halt besteht KTRR für Kernel Text Read Only Region. Also eine Region im Kernelspeicher, der nur gelesen werden soll, aber nicht geschrieben werden soll. Und es gibt zwei starke Garantien. Die erste Garantie ist, dass alle Schreibprozesse in diesem Speicherbereich versagen mit einem Fehler. Und mit dieser Garantie wird sichergestellt, dass was durch die Secure Bootchain ursprünglich dort hingeschrieben wurde, sich nicht mehr verändert. Und auch die zweite Garantie ist, dass alle Abfragen von Anweisungen von außer dieser Region scheitern ebenfalls, so dass man den Kernelcode nicht direkt beeinflussen kann oder nicht beeinflussen kann. Wie sieht das im Detail aus? Also das ist jetzt stark vereinfacht. Hier haben wir die CPU-Kerne, also mit sechs Kernen. Die Lila-Boxen sind die mathematischen Einheiten oder irgendwelche bestimmten Einheiten. Und dann haben wir den Speicherkontroller, den AMCC, und das ist zu dem Arbeitsspeicher verbunden. Und der Kernel ist auch in diesem Speicherbereich mit abgelegt, und das ist der beschützte Speicherbereich. Und der erste Schritt, der passiert, um das alles abzusichern, ist, das ist etwas, was innerhalb eines einzigen CPU-Kern jetzt wie hier abgewildet passiert. Und wir haben in diesen MNUs bestimmte Start- und End-Adressen für Bereiche im Rahmen, die dann halt entsprechend abgesichert werden. Und die CPU überprüft dann für jede Anweisung, die ausgeführt wird von ihr selbst, ob sie eventuell diese Garantien einhält oder halt nicht einhält. Also wenn wir aber versuchen, in diesen Bereich reinzuschreiben, dann wird die CPU blockieren und einen Fehler produzieren. Und ja, die Anweisung schlägt Fehl. Wenn man jetzt auf ähnliche Art und Weise versucht, eine Anweisung auszuführen, die außerhalb dieser geschützten Regionen liegt, dann sorgt die CPU ebenfalls dafür, dass das nicht erfolgreich ist. Und hier ist jetzt ein neues Bild mit den CPU-Kern. Und die nächste, aber das ist immer noch nicht das vorstellige Bild, dass wir brauchen, um den Speicher zu schützen, weil es noch weitere Geräte gibt, die mit dem System verbunden sind. Das heißt, um sich hier zu schützen gegen bösartige Zusatzgeräte, gibt es weitere Register in der AMC-C, die dann auch diese Start- und End-Adressen für den Speicher vorliegen haben. Und dann auch diese Garantien. Und das ist jetzt das Bild, wie die Hardware jetzt aussieht. Aber es ist immer noch nicht das vollständige Bild, da ist immer noch ein Randfall, den man betrachten müsste, wenn man die GPU-Kern in einem Randfall, den man betrachten müsste. Wenn jetzt ein CPU-Kern in den Schlafmodus geht, dann verlieren diese MMU-Register ihre Informationen. Und das betrifft halt auch diese MMU-Register, wenn der Schlafmodus aktiviert wird. Und sie werden halt auf 0 gesetzt. Und wenn die CPU wieder aufwacht vom Schlafmodus, dann muss das halt wieder zurückgeschrieben werden, diese Information. Und dies ist der erste, das erste Stück Code, das ausgeführt wird, wenn die CPU wieder aufwacht. Und was Apple getan hat, ist, dass sie Code zu dem Reset-Vector hinzugefügt haben, die die mithilfe von diesen globalen Variablen die Werte zurückgeschrieben haben. Und sobald diese Werte in den Allgemeinregistern geschrieben hat, werden sie übertragen und sobald der Code ausgeführt wird, ist der Speicher wieder abgesichert. Und man kann nicht mehr. Und die ursprünglichen Garantien gelten wieder. Und jetzt haben wir einen großen Überblick über das, wie das alles funktioniert. Und jetzt ist natürlich die Frage, wie können wir das System ausnutzen? Es gibt zwei historische Exploits oder zum Beispiel Umgehungsmaßnahmen. Die erste Umgehung wurde relativ früh gefunden, und zwar zu, was Luca Todesco seinerzeit gefunden hat, war, dass Apple eine bestimmte ausführbare Instruktion KernelCache gelassen hatte, die aber nicht ausführbar sein sollte eigentlich. Und mit dieser Anweisung wurde das TIT ein weiteres spezielles Register gesetzt. Und wenn man dann das entsprechende Register selber manipulieren konnte, konnte man halt die virtuellen Speicherbereiche ummappen und dann auch den Korn entsprechend in die falsche Richtung lenken. Und dadurch... Also es ist natürlich jetzt wichtig zu wissen, dass KTR schon immer korrekt initialisiert war. Also man konnte jetzt keinen neuen Kernelcode ausführen. Wir können insbesondere auch keine read-only Daten patchen und wir können auch keinen neuen Kernelcode da rein patchen und ausführen. Aber was eben dieser 10.1-Bipass ermöglicht hat, ist, dass man den eigentlich vorgesehenen Bereich der KTRR geschützten Zone reduziert hat auf diese jetzt rotsichtbaren Bereiche. Der zweite Bypass von KTRR war mehr ein Bypass in der Theorie als jetzt wirklich in der Praxis, aber es war auf jeden Fall eine sehr wichtige Inspiration für meine eigene Forschung. Also in iOS 11.1.2 hat INB herausgefunden, dass die Debugging Funktionalität in der Arm-Spezifikation auch in Apples Prozessoren implementiert war und dass man daraus tatsächlich einen kompletten Kernel-Debugger entwickeln konnte. Wenn man sich das Armreferenz Handbuch genau durchliest, dann findet man etwas, das Self-hosted Debugging heißt. Die Architektur stellt Debugregister bereit, auf die man über MSR Instruktion zugreifen kann und man kann die Nutzen um zum Beispiel Breakpoints im Kernel-Modus zu setzen, Exception-Handling-Code zu installieren, eigene Exception-Handler zu schreiben. Also man kann im Prinzip den Kernel seinen eigenen Debugger implementieren lassen. Das ist so ein bisschen analog wie wenn man ein KDB benutzen würde, also den Kernel-Debugger benutzen würde, um einen MacBook zu debuggen. Das wurde aber, also der KDB wurde tatsächlich aus dem iOS Kernel entfernt, aber die ganzen Register, um das zu benutzen, sind halt eben noch da. Und was INBM herausgefunden hat, ist, dass man Return-Oriented-Programming benutzen kann, um diese Register korrekt zu setzen und daraus dann einen vollständigen Kernel-Debugger zu bauen. Ja, das funktioniert dann auch mit LDB, war auf jeden Fall sehr, sehr nützlich und ja, man kann dann Breakpointing machen, Single-Stepping machen, ja im Prinzip Sachen im beliebiger Reihenfolge da ausführen zu lassen. Es ist nicht ganz so wie ja komplett freigewählte Code-Ausführung, aber es ist ziemlich nah dran. Ich habe das Projekt angefangen mit dem Ziel, irgendeinen Kater-ER Bypass zu finden. Und ich wollte halt irgendwas finden, was noch mächtiger ist als das, was bisher gefunden wurde. Irgendwas, das persistent ist, auch über mehrere Versionen von iOS. Also ich habe zum Beispiel nach einem iBoot-Fehler gesucht, speziell in den Verifizierungsfunktionen, da habe ich nichts gefunden, dann habe ich mir einige Abschnitte vom armen Architekturhandbuch durchgelesen und ja, habe dann so Sachen gefunden wie komisch geformte TLB oder Page-Table-Einträge, ob man dann da vielleicht, also wenn man irgendwelche kaputten Page-Table-Einträge hat, ob man damit was mit dem TLB machen kann, habe ich aber auch nichts gefunden. Dann habe ich irgendwie so ein bisschen missverstanden, wie Kater-ER funktioniert und hatte gehofft, dass ich irgendeine Möglichkeit finde, den L2-Cache zu korrumpieren, um Kater-ER zu gehen. Also das hat alles nicht geklappt. Und ja, das habe ich dann erst mal alles liegen lassen und was anderes gemacht. Und dabei ist mir aber irgendwann aufgefallen, dass ich eine Kernelpanic verursachen konnte. Und ich hatte da tatsächlich mit Interrupts rumgespielt und es geschafft, dass ich einen CPU-Kern in einer Endloschleife bringen konnte, in der auch Interrupts maskiert waren. Und das sieht man dann auch hier in dieser Kernelpanic, dass das System bemerkt hat, dass eine CPU endlich lange dreht und dass da irgendein Problem vorlegt. Aber was sich daran so interessant fand, war tatsächlich etwas weiter vorne. Und da steht, ja, Versuche, CPU-1 gewaltsam anzuhalten. Was ich aus dem Armhandbuch herausfinden konnte, war, dass es tatsächlich keinen Standard-Weg gibt für einen CPU-Kur, einen anderen anzuhalten. Also ich konnte mich da an keinen standardisierten Weg erinnern. Und dann habe ich wohl gedacht, dass es irgendein proprietäres Interface gibt. Also irgendein spezielles Kontrollregister oder sowas, dass man über Memory-Map.io zu greifen kann, dass ich dann nutzen könnte, um die CPU anzuhalten. Das fand ich auf jeden Fall ziemlich interessant, weil ich sowas noch nie gesehen hatte. Und dann habe ich mir eben die üblichen Security-Engineering-Werkzeuge genommen, um herauszufinden, was da tatsächlich passiert. Ich habe durch den Sourcecode durchgeschaut und nach genau dieser Text aus der Kernelpanic gesucht. Und bin dann bei folgender Funktion angekommen. ML Debug Report CPU, die anscheinend genau das implementiert. Sie nimmt den Index der CPU, die man anhalten möchte. Das heißt, bei einem 6-Kerner wäre das 0 bis 5. Und der Teil, der tatsächlich die CPU dann anhält, ist dann hier etwas weiter unten. Genau diese hier. Es nimmt einen Pointer aus einer Pro-CPU-Daten-Struktur. Der ist als Volatile markiert in C. Das heißt, es ist ein Speicheraufruf. Und dann ist der Code, der tatsächlich die CPU anhält, einfach nur eine einzelne Zeile, in der eine bestimmte magischen Wert in dieses Debug-Register schreibt. Und das sieht mir eben sehr danach aus, dass es ein Memory-Map.io-Register ist. Ich habe da jetzt online keine Ergebnisse gefunden. Aber das bestärkt mich eigentlich nur in meiner Ahnnahme, dass es eben irgendein properitäres Interface ist. Das andere, was ich interessant war, war, dass da noch die ganze Zeit der Stringcore-Side auftauchte. Ich hatte das mal irgendwann gehört, hatte es aber erst mal auch später verschoben. Und tatsächlich gab es nur ein paar Zeilen weiter unten. Eine Funktion, die wir hier sehen, MLD-Bug-Report-CPU-The-State. Die macht ungefähr das Gleiche wie die anderen Funktionen, nur dass sie zusätzlich zum Anhalten der CPU auch noch den Register-Inhalt, der gerade angehaltenen CPU aussieht. Und wie sie das macht, ist tatsächlich relativ bemerkenswert. Man sieht hier ja einen weiteren Zugriff auf dieses Core-Side-Register. Also irgendwas ist da definitiv wichtig. Vielleicht der Block, der diese Funktionalität enthält. Aber ja, der viel wichtiger Teil ist eben diese Vorschleife hier unten. Die geht, literiert die Variable E über die Indices der General Purpose-Register. Und was im Rumpf dieser Schleife passiert, ist, dass sie zuerst den Nomir schon opcode, also der Instruktion passiert, berechnet und schreibt das in das System-Register Debug-DTR. Also das ist keine Instruktion, die schon irgendwo im Kernelcash existiert, sondern der generiert genau in dieser Zeile die Instruktion, den Opcode für diese Instruktion. Und schreibt das dann eben in dieses entsprechende Register und liest dann den Wert, der in diesem Debug-Rab-DTR-Register steht und schreibt das in den Output-Puffer XI. Und das ist wirklich interessant, weil was ich vermute, was es tut, ist, dass es halt eben dynamisch generierte Instruktionen ausführt. Und das widerspricht wirklich dem Sicherheitsmodell, das KTR eigentlich implementieren soll. Weil KTR soll ja eigentlich garantieren, dass nur die Instruktionen, die im Kernelcash stehen, tatsächlich ausgeführt werden. Aber der Code, der hier steht, erweckt den Eindruck, dass tatsächlich jeder Code, den man möchte, den man möchte, auf der CPU ausgeführt werden kann. Also nur weil es diesen Code in dem XNU-Körner gibt, um das zu machen, heißt jetzt nicht, dass es auch tatsächlich benutzt werden kann. Aber ja, ich habe dafür eben ein kleines Testprogramm geschrieben. Ich hatte da einen alten Kernel-Exploit, den ich nachher umlegen hatte und habe dann was zusammengehackt, dass dann eben genau diese Funktion aufrufen würde und einen entsprechenden Output-Puffer übergeben und habe dann eben den Inhalt dieses Output-Puffers ausgegeben. Und was man hier sieht, ist, dass dieser Ausgabenpuffer tatsächlich so aussieht wie ein Hoffenregister. Also, ein paar Garten sind ein bisschen komisch, aber der Wert von CPSR sieht tatsächlich ziemlich korrekt aus. Es sieht tatsächlich aus wie eine CPU, die im Kernel-Mod läuft und der Wert von PC sieht nicht aus wie eine normale Kernel-Virtual-Adresse aus. Die fangen normalerweise mit FFFF und so an, sondern es sieht so ein bisschen aus wie eine physische Adresse. Zum Beispiel, die vom, also ich habe dann ein bisschen rumgeguckt und das ist tatsächlich die Instruktion vom Reset-Vector. Und das wird jetzt wirklich, wirklich interessant, weil, was das ja eben vermuten lässt, ist, dass wir tatsächlich die Ausführung eines bestimmten CPU-Kerns anhalten können, während es noch den Reset-Vector auswirkt. Und das, wie wir uns erinnern, ja, bevor die MMU tatsächlich eingeschaltet ist und bevor die MMU angeschaltet ist, läuft ja auch KTRR nicht. Und das heißt, wir haben da den Schutz, den KTRR bietet noch nicht. Also, wie benutzen wir das dann? Und es gibt eine noch fundamentalere Frage. Was ist jetzt eigentlich dieses Core-Site genau? Es war, es ist halt schwierig, etwas für mich auszunutzen, wenn ich nicht vor wirklich verstehe, wie es funktioniert. Und ich habe dann im Arm Referenz in der Anleitung geschaut, wie die, wie Core-Site beschrieben ist. Und dort sieht man dann halt das external, also das externe Debug, die Debug-Schnittstelle. Und man kann halt sehen, dass der Self-hosting-Colonel-Debugger hat ebenfalls diese Schnittstelle benutzt und man nutzt dann diese Register, um die entsprechenden Anweisung zu geben. Und... Also, die Art und Weise, wenn man auf diese Register zugreift, funktioniert über memory-map.io anstatt MSR Instruktionen. Aber das bedeutet das halt letztendlich die Funktionalität, um einen Körner Debugger zu bauen, immer noch da ist, obwohl die return-oriented Program Engages, die ihren benutzt hat, wegentfernt wurden, gibt es halt immer noch dieses Interface. Und tatsächlich ist das nicht das erste Mal, überhaupt nicht das erste Mal, dass jemand die Bankeregister benutzt hat in einem Arm-Prozessor, um irgendeine Form von Privilege-Escalation-Attacke zu machen. Und der Meiste von 2019 Exploits haben ebenfalls diese Debugging-Register verwendet, um die, also auch auf Android-Telefonen, wurden diese ebenfalls benutzt, um Exploits zu schreiben, so dass man mit diesen Instruktionen verschiedene CPU-Kern untereinander steuern konnte und dadurch Anweisung auszuführen, die dann zu Speicherzugriffen geführt haben, die halt eigentlich nicht passieren dürfen. Und also CoreSight ist ein externes, eine externe Debug-Schnittstelle. Und es ist eine Schnittstelle, die auf dem Chip selber ist. Und diese Schnittstelle ist tatsächlich gut dokumentiert, im Arm acht Handbuch. Und man kann mithilfe dieser Schnittstelle Breakpoints und Watchpoints setzen und auch gezielt bestimmte Anweisung ausführen. Und das Schöne ist halt, das ganze System ist dadurch, oder diese Debugging-Schnittstelle ist mächtig genug, um damit beliebige Debugging-Manöver durchzuführen und auch halt einen Kernel-Debugger zu schreiben. Und wir haben jetzt diese Debug-Register und wir können jetzt die Ausführung stoppen und kontrollieren. Und mithilfe des externen Debug-Interface können wir die Lockdown-Anweisung blockieren. Und so dass wir dann, wenn wir jetzt hier zum Beispiel den Reset-Vector haben, gehen wir durch die einzelnen Anweisung. Und bevor wir dann die Absicherung machen, können wir einfach diesen Wert hier auf Null setzen und dann die Schutzfunktion überspringen. Und das ist natürlich eine nette Idee. Aber wir haben immer noch nicht alle Komponenten, die wir benötigen. Also wir können die CPU stoppen. Wir können die Ausführung weiter laufen lassen. Aber was wir wollen ist die CPU neu starten oder starten, nachdem die CPU gestoppt wurde. Und wir wollen natürlich auch unsere Veränderungen mit einbringen. Und es gibt noch eine weitere Sache, die berücksichtigt werden muss. Wir benutzen halt eine CPU, eine andere CPU zu beeinflussen. Und diese CPU-Zurücksetzungen passieren ständig. Und das Ganze passiert halt alle paar Sekunden. Und wir müssen daher diese Kontrolle umgehungständig. Und jedes Mal, wenn ein CPU-Kern zurückgesetzt wird, müssen wir halt wieder reingregen und die Kontrolle übernehmen. Und daher habe ich überlegt, dass ich mir dieses proprietäre System, das ich früher schon erwähnt habe, nochmal anzuschauen. Also es gibt noch ein paar Bits, die nicht dokumentiert sind. Und ich wollte einfach mal schauen, was passiert, wenn ich jetzt bestimmte Bits setze. Und naja, es war eigentlich nur dummes Glück, dass ich dann die Funktionalität gefunden habe, mit der ich dann die CPU komplett kontrollieren konnte. Und dann habe ich halt wirklich herausgefunden, wie ich die CPU stoppen und wieder starten kann. Und dann halt auch den Reset-Prozess besser unter Kontrolle hatte. Und das Schöne ist, das funktioniert jetzt alles wunderbar. Und wir müssen uns sicherstellen, dass sobald wir diesen Zweig erreichen, dass wir dann halt hier den großen Sprung machen und dadurch wird die Speicherabsicherung niemals vollzogen. Und es sieht halt dann, also sobald wir dann halt den Hijack gemacht haben, können wir halt alles machen, was wir wollen, im Kernel-Mode. Ja, ich habe mal ein paar mehr Sachen. Danke. So, nachdem wir jetzt KTRW umgang haben, wollte ich natürlich jetzt einen vernünftigen Debugger basierend darauf schaffen. Und es gab einige Schritte, die ich gehen musste. Einige davon dachte ich, also von einigen von diesen Schritten dachte ich, ich könnte sie nie überwinden. Also zunächst einmal müsste man den Kernel neu mapen. Und wir haben halt zu diesem Zeitpunkt noch nicht die Möglichkeit, den Kernel-Speicher zu überschreiben. Eine weitere Herausforderung war, eine Kernel-Extension zu laden, also eine Kernel-Weiterung. Und wir müssen uns halt auch mit Interrupts beschäftigen, weil sobald eine CPU gestoppt wurde, kann sie auch keine Interrupts mehr behandeln. Und das ist halt auch ein Problem in der Praxis. Die Kommunikationskanale muss auch entsprechend berücksichtigt werden. Und ich muss natürlich dann eine passende Schnittstelle für GDB schaffen. Also wir haben prinzipiell die Fähigkeit, beliebigen Shellcode auszuführen, aber wir können den Kernelcode selber noch nicht patchen. Und auch wenn wir den Code jetzt außerhalb der nur lesbaren Regionen ausführen können, ist es immer noch so, dass die Read-Only-Region immer noch vollbeschützt sind. Und das Problem ist halt, dass wir halt die Pagetable ändern müssen. Und das Ding ist halt, dass die Wurzel der Pagetable Hierarchie ebenfalls in der KTRR-Region liegt, die immer noch nur lesbar ist. Und ich habe dann nochmal geschaut, wie der Exploit von Luca aussah und das war, was er gemacht hat, war halt, dass er den Kernel in neue schreibbare Speicherbereiche geschrieben hat. Und das habe ich dann auch gemacht. Also ich habe den neuen, den Kernel in einem anderen Bereich gehabt, aber immer noch ein Verweis auf die Pagetable gehabt im geschützten Bereich. Und dann habe ich halt dafür gesorgt, dass die neuen Ergebnisse dann in einen Bereich geschrieben wurden, auf den ich immer noch voll zugefahrte. Und damit hatten wir dann die Möglichkeit, den Kernel zu patchen. Und das nächste Problem war es, Kernel-Extensions zu laden. Und das war dann tatsächlich jetzt nicht mehr so schwer, nachdem ich den Kernel selber... Also wenn man eine Kernel extension hat, dann will man ja irgendwo Funktionen im Kernel aufrufen. Das heißt dynamisch, linken ist dafür notwendig. Da müssen wir die Pagetables modifizieren, sodass die gerade geladene Kernelfunktionen ausgebaut wird. Und dann müssen wir den Eintrittspunkt dieser Kernelfunktion aufrufen, um sie zu starten. Um diesem High-Level-Design fangen wir jetzt mit dem anderen Kernel die Pagetable zu entwerfen. Was tatsächlich rausgegangen, ist ein relativ einfaches Design. Wir haben einen Core auf der CPU, den wir den Monitor kehren. Der ist komplett reserviert für den KTHW, also für diesen neuen Debugger, den wir schreiben wollen. Und der wird dann für keine Anwendungen oder sonstige Threads verwendet. Wenn man einen Breakpoint oder einen Watchpoint setzt, dann für einen bestimmten Kern setzt, dann wird dieser Kern angehalten und in den Debugzustand gesetzt. Und der Monitor-Kern wird dann dementsprechend einfach nur in einer Endloschleife checken, ob irgendeine von den CPUs gerade angehalten ist, was dann quasi das Signal ist dafür, dass sie in den Breakpoint angekommen ist. Das wird dann in U-Körne ganz normal an den User Space LLDB Debugger weitergeleitet. Und dann kann der ganze übliche Stack ganz normal arbeiten wie sonst. So sieht das dann normalerweise aus. AWP Panic. Und das war eben ein Problem. Ich habe dann irgendwann verstanden, dass das von dem sogenannten Always-On-Prozess, also den Prozess immer an ist, verursacht wird, der Interrupts an den Hauptprozessor sendet. Und diese Interrupts, die von diesem Always-On-Prozessor gesendet werden, müssen gehandelt werden. Ansonsten wird dieser AWP paniken und dabei das gesamte System crashen. Ich habe dafür dann die Watchdog-Timer Kern-Erweiterung Reverse-Engineered und herausgefunden, wie man diese Funktionalität ausschalten kann. Aber es gab noch Ante-Interrupts, die ich nicht ausschalten konnte. Und ich vermute irgendwie, dass die Geräte, bei denen die Entwickler-Fuses noch drin sind, dass man da diese Interrupts irgendwie ausschalten kann. Aber ich gehe davon aus, weil Apples-Engineere ja im Prinzip auch diesen gleiche Methode verwenden, um den Kern-Erweiterung zu debacken. Und das ist ja nicht so toll, wenn Sie nach demselben paar Sekunden den Prozessor angehalten haben zum Debacken und dann die Ausführung wieder fortsetzen, dann das ganze System panikt. Also die haben da intern bestimmt irgendwas Sinnvolleres, zum Beispiel diese Dev-Fuses. Den Hack, den ich jetzt aber habe, weil ich ja keine App-Engineered bin, ist eben, dass ich diese Dev-Fuses... Entschuldigung, die letzte Zeit habe ich nicht gesehen. Das zweite Problem war, dass es passieren kann, dass der Monitor Kern in den Interrupt-Handler springen kann zu jedem möglichen Zeitpunkt. Und das bedeutet, wenn irgendeiner der zu debagenden Kerne anhält und aber dabei ein Spin-Lock hält, dann ist ja die einzige Möglichkeit, dass dieser Spin-Lock freigegeben werden kann, dadurch, dass der gerade zu debackende Kern wieder weiterläuft. Und das geht aber nicht, weil er gerade angehalten ist. Das heißt, wir laufen hier in den Deback, in den Deadlock. Und der Hack dafür ist, dass wir tatsächlich damit in den Debakten... Also, der Workaround dafür ist, dass wir tatsächlich nur damit umgehen können, indem wir den normalen Interrupt, indem wir den Interrupt auf den zu debackenden Core behandeln. Und ja, also das bedeutet, dass eben Interrupts maskiert werden müssen, während wir in einer Code-Region sind, die in der möglicherweise Interrupts auftreten können. Während Interrupts das Able sind, sind wir eben in so einer möglichen kritischen Region und dann können wir den Kern noch nicht direkt anhalten, sondern machen das erst ein bisschen später. Und nachdem ich diesen Hack zur Anwendung gebracht habe, sind dann meine Probleme mit den Interrupts verschwunden. Also das ist nicht jetzt an dem Punkt, wo wir Code, wo wir in der Kernel extension im Kernel laufen haben und brauchen jetzt eigentlich nur noch einen Kanal, um LEDB auf dem Laptop mit dem iPhone Kernel zu verbinden. Ich habe mir da verschiedene Möglichkeiten überlegt, haben immer vor und nachteile. Seriell ist natürlich ziemlich nett und einfach zu implementieren. USB ist mein, fand ich ziemlich gut, weil es ziemlich schnell ist. Aber Wi-Fi hatte ich auch noch als Option, falls die Anarbeit nicht funktionieren, aber es war eigentlich nicht wirklich meine Präferenz. Aber was viel ausstattgebender war, war tatsächlich die Nachteile jeder der jeweiligen Techniken. Bei Seriell braucht man spezielle Hardware, um diese Kommunikation herzustellen mit dem iPhone und das steht ja im Widerspruch zu meinen ursprünglichen Zielen, dass ich keine spezielle Hardware brauche für meinen Angriff. Man sollte ja einfach mit ganz normaler Apple-Hardware, die man mit Apple-Harden kaufen könnte, einen Angriff machen können. Die anderen Probleme, wie bei USB und Wi-Fi hatten das gleiche Problem, nämlich dass man jeweils speziellen Code schreiben müsste, weil das Problem ist eben, dass wenn wir einen Breakpoint treffen und der Code, der diesen Breakpoint ausgelöst hat, hält irgendein Log, der hält irgendein Log, der von dem Original-Triber verwendet wird, dann haben wir im Prinzip auch wieder das Deadlock-Problem von eben. Das heißt, egal welchen Kommunikationskanal wir verwenden, da müssen wir immer einen eigenen Treiber entwickeln, der komplett eigenständig ist und da haben wir ihn nicht vom restlichen können. Und da fand ich den USB-Stack etwas weniger schmerzhaft. Ich habe mit etwas Nachgugeln herausgefunden, welcher Hardware-USB-Kontroller im iPhone verwendet wird. Das ist ein USB-Kontroller von Synopsis. Der heißt der Designware Highspeed USB 2.0 und der Go-Controller. Und was ein bisschen unglücklich dabei ist, ist, dass er properitär ist, dass die Schnittstelle, die zur Kommunikation verwendet ist, kein Standard-USB-Interface. Das heißt, man kann nicht einfach irgendeinen Open-Source-Triber verwenden, dafür um diesen Stand-alone-Triber für den Debugger zu implementieren. Und dann habe ich nach einem Datenblatt gesucht, aber bin dann in ein Lock-In-Fence da gelaufen. Also ich kam nicht an die Datenblätter dran. Also, das schien irgendwie alles ein bisschen problematisch. Aber was ich gefunden habe, war, waren Open-Source-Header-Dateien für diese Hardware. Es gibt auch Open-Source-Triber dafür, aber alle, die ich gefunden habe, haben das im Host-Modus gemacht. Das heißt, irgendwie als Laptop und nicht als Gerät, dass man da gereinsteckt. Und die haben also nicht für mich funktioniert. Aber ich konnte eben diese Header-Dateien verwenden, die die Registerdefinition enthielten. So, der einzige Code, den ich mir vorstellen könnte, der das enthält, der so eine vollständige, eigenständige Implementierung enthält, der genau diesen Chip tatsächlich betreibt, war tatsächlich der Secure-Rom vom iPhone selbst. Das ist das allererste Stück Code, das auf dem Anwendungsprozess läuft, wenn das iPhone startet. Und es braucht ein USB-Stack, um mit einem Computer zu kommunizieren, zum Beispiel für DFU-Firmware-Upgrades. Und ich habe also einfach diesen Secure-Rom-Dump genommen, den man online finden kann, habe es in IDA gesteckt, und den Teil reverse-engineered, und den Code bis zuerst reverse-engineered und dann nochmal in C9 implementiert. Also, das war etwas schwerzhaft. Aber der Vorteil war, dass ich tatsächlich mein iPhone als ein spezielles KTRW-USB-Gerät, dass mein iPhone gegenüber dem Laptop als spezielles KTRW-USB-Gerät auftreten konnte. Und damit war dann der letzte Schritt, tatsächlich einfach den GDB-Stab zu implementieren. Das ist relativ einfach, compared zu dem anderen Kram in diesem Projekt. Die GDB-Spezifikation ist Open Source. Man muss eigentlich nur ein bisschen was pausen und dann die externe Debug-Schnittstelle treiben. Und als ich das hatte, hatte ich dann tatsächlich die Möglichkeit, ein Production-Iphone, also, dass man einfach so kaufen kann, einfach nur mit einem normalen USB-Kabel zu debaggen ohne irgendwelche spezielle Hardware. Und hier mache ich hoffentlich eine relativ schnelle Demo. Ich habe ein iPhone, das ihr hier sehen könnt. Und ihr könnt den Screenshot auf dem Laptop sehen können. Also, ihr könnt quasi den Screenshots hier sehen. So, was ich jetzt mache, jetzt werde ich jetzt hier die App stoppen, die die Kernelerweiterung startet. Und jetzt werden wir mit LLDB uns verbinden. Okay. Und LLDB hat das Gerät als iOS-Gerät erkannt. Und wir können jetzt die Ausführung weitermachen. Ich kann es jetzt leider nicht auf dem Display zeigen. Aber für die Leute in der ersten Reihe, ihr könnt sehen, das Gerät ist wieder, er ist antwortet, wieder auf meine Eingaben. Also, ich kann jetzt beispielsweise hier ein Breakpoint setzen auf dem Systemaufruf Mincor. Ich habe eine Anwendung auf dem Gerät, das Mincor aufrufen wird mit diesen bestimmten Argumenten. Und für diese Demo, um es schnell zu machen, habe ich die App halt schon vorinstalliert. Und das stoppt halt die CPU. Das Telefon reagiert nicht mehr auf meine Eingaben. Und wir können jetzt uns den Speicher anschauen und auch den Beschützenspeicher anschauen. Wir können jetzt Watchpoint setzen und verschiedene Debugging-Aktionen durchführen. Wir setzen hier ein Watchpoint und wir führen das Programm weiter aus. Und hier könnt ihr die Anweisung sehen, die diesen Watchpoint setzt. Wir können den Breakpoint wieder entfernen und das Ganze weiter laufen lassen und das Telefon reagiert wieder. Applaus. Cool. Also, vielen, vielen Dank. Der Debugger Quellcode ist hier auf GitHub zugänglich. Ich habe auch einen Blog-Post gemacht, wie ich halt dazu kam, den Debugger zu entwickeln und auch die ganzen Sicherheitslöcken zu finden. Und das ist auch zum Teil auf dem... Passiert auch teilweise auf den Bootraum-Exploit. Vielen Dank. Okay. Keine Fragen aus dem Internet. Vielen Dank für den tollen Vortrag. Am Anfang hast du den Export gezeigt und du hast halt gesagt, dass alles, was mit dem Export möglich ist, kann ich auch machen, aber du hast halt gesagt, dass das das Thema nicht patchbar ist. Und ist es jetzt möglich, das laufen zu lassen, ohne das iPhone erst zu entsperren? Also meinst du den Bootraum-Bug oder die Debugregister oder beides? Eigentlich alles. Also ich weiß nicht wirklich, das ist nicht wirklich meine... da habe ich nicht so viele Fachkenntnisse drin. Es gibt mit Sicherheit Leute, die zum Beispiel physische Attacken daraus bauen könnten. Die Debugregister, die ich hier verwende, sind jetzt nicht wirklich nützlich für eine Remote-Attacke, weil man den CPU dabei relativ schnell resett und daneben der Karte bypass vorbeigeht. Und das heißt, ganz unabhängig davon, sobald jemand Körner Zugriff hat, ist das Gerät eigentlich sowieso komplett kompromittiert. Und ja, so hängt natürlich vom Fred-Model ab, ob das tatsächlich eine Gefahr darstellt. Hast du dir den Liedungskollem angeschaut, wie es da aussieht? Also das war tatsächlich ziemlich lustig. Genau dann, als ich fertig war mit dem USB-Stick, dann... genau, also als ich den USB-Stick fertig implementiert war, habe ich rausgefunden, dass ich tatsächlich einfach nur für die falschen... nach den falschen Sachen gesucht habe und die Dateien, die tatsächlich diesen Treiber beinhalten, im Device-Mode, die hießen einfach anders, als ich erwartet habe. Also, ja, man lernt eben beim Machen. Hi, great talk, I really enjoyed it. Wirklich guter Vortrag. Ein kurzer Kommentar. Das ist das erste Mal, dass es... das ist das erste Mal, dass es... das ist das erste Mal, dass es... das erste Mal, dass es... das erste Mal, dass es... die Versorgung innerhalb von Registers haben, ist ebenfalls auf ähnlicher Weise schon entdeckt. Also diese Sicherheits-Look oder diese Mechanismen, du hast den USB-Stick von Secure Rom extrahiert, hast du auch Checkmate gefunden? Also zu deinem Kommentar zuerst mal, es gab einen ganzen Haufen Leute, die ähnliche Möglichkeiten oder Schwachstellen gefunden haben, also nichts, was ich hier in diesem Projekt gemacht habe, originale Arbeit, sondern es baut auf der Arbeit von anderen Leuten auf. Die Frage, ob ich jetzt Checkmate entdeckt habe oder nicht. Das erste Mal, als ich mein Eiboot angeschaut habe, war ich ziemlich verwundert, dass es so kompliziert ist. Also ich wollte es eigentlich wirklich nicht anfassen. Und ja, das habe ich nicht entdeckt. Okay, keine weiteren Fragen. Eine große Runde Applaus für unseren Vortraineln. Dies war die Übersetzung von dem Talk.