1 00:00:00,000 --> 00:00:16,070 35C3 Vorspannmusik 2 00:00:16,070 --> 00:00:25,390 Herald: Gut dann wollen jetzt beginnen. Wer von euch hat schon mal eine E-Mail 3 00:00:25,390 --> 00:00:33,960 gekriegt mit einem Anhang? Wer von euch hat eine E-Mail bekommen mit einem Anhang 4 00:00:33,960 --> 00:00:40,410 von einer euch unbekannten Person? Das sind erstaunlich wenige, so 20 Prozent. 5 00:00:40,410 --> 00:00:47,671 Wer von euch hat den schon mal aufgemacht? 3, 4. Wer von euch kennt jemanden, der schon 6 00:00:47,671 --> 00:00:55,620 mal einen Anhang aufgemacht hat? Ja deutlich mehr. Wer von euch musste die 7 00:00:55,620 --> 00:01:03,420 Probleme beseitigen, die dadurch entstanden sind? Ja auch so 10 20 Prozent 8 00:01:03,420 --> 00:01:12,170 würde ich sagen. Ja es ist natürlich eine ganz gute Idee, sich zu überlegen, ob man 9 00:01:12,170 --> 00:01:16,220 denn jetzt eine Rechnung oder ein Angebot auf machen möchte, was man von einer 10 00:01:16,220 --> 00:01:22,580 völlig unbekannten Person aus dem Internet bekommen hat. Und was da passiert, wenn 11 00:01:22,580 --> 00:01:26,659 man es tatsächlich täte, das wird uns jetzt haggl erläutern. Applaus. 12 00:01:26,659 --> 00:01:30,990 Applaus 13 00:01:30,990 --> 00:01:46,450 Haggl: Was? Das sollte so nicht aussehen, Moment, warum sagt mir das keiner? 14 00:01:46,450 --> 00:02:15,700 So, hallo, dann können wir jetzt ja anfangen. Ja also danke für die schöne Einleitung. 15 00:02:15,700 --> 00:02:20,690 Schön, dass ihr alle da seid, dass ihr so zahlreich erschienen seid. Wie in jedem 16 00:02:20,690 --> 00:02:27,160 Jahr eigentlich, gab es auch in 2018 - ich schiebe mal eben die Maus da weg - 2018 17 00:02:27,160 --> 00:02:31,300 wieder ein paar schöne Beispiele, oder schön ist in Anführungszeichen zu setzen, 18 00:02:31,300 --> 00:02:33,560 Beispiele von Sicherheitslücken, die ziemlich gravierend sind und die 19 00:02:33,560 --> 00:02:40,000 geschlossen werden, glücklicherweise, gingen direkt am Anfang des Jahres los. Im 20 00:02:40,000 --> 00:02:43,670 Januar wurden im Firefox und mithin auch im tor-Browser, der ja drauf basiert, ein 21 00:02:43,670 --> 00:02:49,910 paar Sicherheitslücken geschlossen, für die man nur eine Webseite besuchen 22 00:02:49,910 --> 00:02:53,910 musste und dann sind da intern irgendwelche Buffer Overflows passiert und im 23 00:02:53,910 --> 00:02:58,450 schlimmsten Fall konnten Angreifer damit halt beliebigen Code ausführen. Ein 24 00:02:58,450 --> 00:03:01,860 weiteres Ding aus diesem Jahr, da habe ich leider keine schöne Pressemitteilung zu 25 00:03:01,860 --> 00:03:07,150 gefunden, nur so einen CVE-Artikel. Der Adobe Reader, mal wieder, übrigens guckt 26 00:03:07,150 --> 00:03:12,989 mal wie viele Sicherheitslücken der hat, das ist enorm. Da war auch was drin mit 27 00:03:12,989 --> 00:03:17,560 einem Buffer Overflow und ebenfalls arbitrary code execution. Heißt, ein 28 00:03:17,560 --> 00:03:20,930 Angreifer kann beliebigen Code auf dem Rechner ausführen. Drittes Beispiel, gar 29 00:03:20,930 --> 00:03:26,099 nicht so lange her, ist eigentlich im letzten Jahr gewesen, und zwar die beiden 30 00:03:26,099 --> 00:03:31,190 Würmer Petya und WannaCry. Das waren so sympathische Ransomwares, die die 31 00:03:31,190 --> 00:03:35,959 Festplatte verschlüsseln und den Besitzer dann auffordern, Bitcoins zu überweisen, an 32 00:03:35,959 --> 00:03:40,200 eine bestimmte Adresse, damit der Rechner wieder frei geschaltet werden kann. Auch 33 00:03:40,200 --> 00:03:45,780 die waren beide, also Teil der Angriffe, die die genutzt haben, funktionierten über 34 00:03:45,780 --> 00:03:50,060 Buffer Overflows. Man sieht also, es ist ein Thema mit dem man sehr viel machen 35 00:03:50,060 --> 00:03:55,110 kann und deswegen reden wir da jetzt ein bisschen darüber. Das ist der grobe 36 00:03:55,110 --> 00:03:57,760 Fahrplan, es gibt jetzt so eine kleine Vorstellungsrunde, ich sage etwas zu mir, 37 00:03:57,760 --> 00:04:02,349 frage was über euch, sag was zum Vortrag. Danach machen wir ein paar Grundlagen, die 38 00:04:02,349 --> 00:04:05,830 zum Teil sehr technisch und zäh sind, ich bitte das zu entschuldigen, aber ganz ohne 39 00:04:05,830 --> 00:04:12,090 geht es leider nicht. Und dann erkläre ich, wie halt der Exploit funktioniert, so 40 00:04:12,090 --> 00:04:16,289 ein Stack Buffer Overflow Exploit und zum Schluss gibt es, wenn die Demo-Götter uns 41 00:04:16,289 --> 00:04:20,320 weiter gewogen sind, eine Demonstration, wo ich meinen eigenen Rechner halt mit 42 00:04:20,320 --> 00:04:28,630 einem verwundbaren Programm übernehme. Also über mich: Ich bin im Chaos und 43 00:04:28,630 --> 00:04:34,050 Hackspace Siegen aktiv und treibe da so ein bisschen mein Unwesen, habe so halb 44 00:04:34,050 --> 00:04:38,120 den Hut für "Chaos macht Schule" und die Cryptoparties auf. Wenn es sich nicht 45 00:04:38,120 --> 00:04:42,639 vermeiden lässt, mache ich noch Infrastruktur und ähnliche Geschichten. In 46 00:04:42,639 --> 00:04:46,530 meinem sonstigen Leben bin ich Informatiker, ich programmiere kleine 47 00:04:46,530 --> 00:04:52,430 Mikrocontroller für Soundsysteme, ich mache Judo und bin Musiker. Meine 48 00:04:52,430 --> 00:04:57,190 Lieblingsspeise ist Dal. An dieser stelle herzlichen Dank an das Küchenteam, die uns 49 00:04:57,190 --> 00:05:01,240 während dem Aufbau sehr gut verpflegt haben, unter anderem mit Dal. So, bisschen 50 00:05:01,240 --> 00:05:07,130 was über euch. Ein kurzes Funktionscheck: Wer hört mir zu und ist in der Lage und 51 00:05:07,130 --> 00:05:13,490 gewillt, seinen Arm zu heben bei Fragen, die zutreffen? Das sind ungefähr alle, 52 00:05:13,490 --> 00:05:17,180 cool. Dann: Wer weiß, wie so ein Rechner aufgebaut ist, Stichwort 53 00:05:17,180 --> 00:05:21,880 Rechnerarchitektur, Rechenwerk, Steuerwerk, so was? Das sind auch 54 00:05:21,880 --> 00:05:27,130 erstaunlich viele, okay. Wer hat schon mal programmiert? Im Idealfall mit C, das sind 55 00:05:27,130 --> 00:05:34,030 ungefähr alle. Wer hat schon mal gehört, was ein Stack ist? Was ein Buffer Overflow 56 00:05:34,030 --> 00:05:41,610 ist? Wer hat sich bei allem gemeldet? Ihr werdet euch langweilen! lacht Der 57 00:05:41,610 --> 00:05:46,600 Vortrag ist nämlich, ich habe versucht, ihn möglichst einfach zu halten, weil 58 00:05:46,600 --> 00:05:49,470 inspiziert inspiriert, entschuldigung, inspiriert ist er von einem 59 00:05:49,470 --> 00:05:52,560 Arbeitskollegen, den ich eigentlich für sehr kompetent halte, und der sich auch 60 00:05:52,560 --> 00:05:56,759 auskennt mit Mikrocontrollern, mit Assemblycode und der mich irgendwann mal 61 00:05:56,759 --> 00:06:01,411 fragte, oder mehr im Nebensatz beiläufig erwähnte, dass er nicht verstünde, wie 62 00:06:01,411 --> 00:06:07,610 denn eigentlich sein kann, dass ein PDF einen Rechner übernehmen kann. Challenge 63 00:06:07,610 --> 00:06:11,190 accepted habe ich mir gedacht, das muss man doch irgendwie erklären können. Und 64 00:06:11,190 --> 00:06:15,419 dann habe ich den Vortrag gemacht, habe hier in den Talk eingereicht in Pretalx, 65 00:06:15,419 --> 00:06:18,539 der wurde dann halt paar Wochen später auch angenommen, dann habe ich mir den 66 00:06:18,539 --> 00:06:21,330 Vortrag, den ich zwei Wochen vorher zusammengeschraubt hatte, noch einmal 67 00:06:21,330 --> 00:06:24,683 angeschaut und geprüft, ob er den Anforderungen entspricht, die ich mir 68 00:06:24,683 --> 00:06:28,550 selber gesetzt habe, festgestellt oh mein Gott, er ist viel zu technisch. Deswegen 69 00:06:28,550 --> 00:06:31,980 habe ich den weiter abgespeckt und versucht, alle nicht nötigen Details, alle 70 00:06:31,980 --> 00:06:34,919 nicht nötigen Fachwörter, alles raus zu streichen, was man nicht unbedingt 71 00:06:34,919 --> 00:06:40,350 braucht, um das Prinzip eines Stack Buffer Overflows oder ein Exploit dessen zu 72 00:06:40,350 --> 00:06:46,139 verstehen. Der Vortrag ist vor 20 Minuten fertig geworden, ich habe ihn noch nie 73 00:06:46,139 --> 00:06:50,759 Probe gehalten, ich habe gestern bei der Demo zweimal meinen Rechner abgeschossen, 74 00:06:50,759 --> 00:06:55,710 insofern bin ich selber sehr gespannt, was jetzt passiert. Also fangen wir an. 75 00:06:55,710 --> 00:06:59,790 Grundlagen: Wie funktioniert ein Rechner? Wenn man es ganz ganz ganz ganz grob 76 00:06:59,790 --> 00:07:05,169 vereinfacht ausdrückt, gibt es irgendwo einen Prozessor, da kommen auf der einen 77 00:07:05,169 --> 00:07:11,680 Seite Daten rein, nämlich Programmdaten, und auf der anderen Seite kommen Daten 78 00:07:11,680 --> 00:07:15,860 rein und raus, nämlich die Nutzdaten, die ich verarbeiten möchte. Das kann, weiß 79 00:07:15,860 --> 00:07:20,550 ich, ein Office-Dokument sein, ein PDF oder halt auch Daten aus dem Internet wie 80 00:07:20,550 --> 00:07:27,889 HTML-Seiten, bei Web-Browsern sind das halt die Daten die rein und raus gehen. Daten 81 00:07:27,889 --> 00:07:35,030 werden intern im Rechner in dem Speicher abgelegt und zwar in Paketen von acht 1en 82 00:07:35,030 --> 00:07:39,639 und 0en. 1en und 0en sind Bits, das wissen ja wahrscheinlich alle. So ein Paket von 83 00:07:39,639 --> 00:07:45,420 acht davon nennt man ein Byte. Jedes Byte hat eine Adresse im Speicher. Und der Witz 84 00:07:45,420 --> 00:07:49,389 ist, dass das hier so, dass was da gezeichnet ist, nicht ganz korrekt ist, 85 00:07:49,389 --> 00:07:53,660 denn Programme und Daten liegen im gleichen Speicher. Das heißt, ich kann es 86 00:07:53,660 --> 00:07:57,900 theoretisch schaffen, den Prozessor dazu zu bringen, Programme auszuführen aus dem 87 00:07:57,900 --> 00:08:02,240 Speicherbereich, wo eigentlich Daten liegen sollten. Das ist schon eigentlich 88 00:08:02,240 --> 00:08:10,139 wie letztendlich so ein Buffer Overflow Exploit funktioniert. Wenn ich den 89 00:08:10,139 --> 00:08:13,580 Prozessor da in der Mitte doch noch mal ein bisschen aufbohre, dann sehe ich, dass 90 00:08:13,580 --> 00:08:18,849 er da drin so einen Registersatz hat. Man nennt das so, Register. Das ist so ein 91 00:08:18,849 --> 00:08:23,940 bisschen vergleichbar mit dem, man könnte sagen, das Kurzzeitgedächtnis von 92 00:08:23,940 --> 00:08:28,580 Menschen, man sagt Menschen ja nach, sie könnten sich so größenordnungsmäßig 7 93 00:08:28,580 --> 00:08:33,829 Dinge gleichzeitig merken, kurzzeitig. So ähnlich ist das bei einem Prozessor auch, 94 00:08:33,829 --> 00:08:38,829 der hat einen sehr begrenzten Satz von Registern, also Speicherzellen, die sehr 95 00:08:38,829 --> 00:08:43,159 schnell sind, aber halt auch sehr teuer sind. Deswegen baut man da nicht so viele 96 00:08:43,159 --> 00:08:46,399 von, das sind die Register. Und dann merkt er sich halt zum Beispiel, wo er im 97 00:08:46,399 --> 00:08:54,069 Programm gerade steht. Also wo im Programmspeicher er gerade steht oder wo 98 00:08:54,069 --> 00:08:59,420 der Stack gerade steht. Der Stack ist ein besonderer Speicherbereich im 99 00:08:59,420 --> 00:09:04,869 Datenspeicher, also eigentlich kein Programmspeicher, der verwendet wird um 100 00:09:04,869 --> 00:09:10,009 Dinge längerfristig abzulegen, also man könnte sagen Langzeitgedächtnis. Naja es 101 00:09:10,009 --> 00:09:14,410 stimmt nicht ganz, aber grob. Und der Stack ist wirklich, der Name ist Programm, 102 00:09:14,410 --> 00:09:17,550 ist wie ein Stapel, ich lege unten was drauf, dann lege ich was oben drauf, lege 103 00:09:17,550 --> 00:09:20,879 etwas weiteres oben drauf, und ich lege auch Dinge oder hole Dinge genau in der 104 00:09:20,879 --> 00:09:26,829 umgekehrten Reihenfolge wieder runter. Also wie ein Stapel Papier eigentlich. Der 105 00:09:26,829 --> 00:09:31,850 wird gebraucht, um bestimmte Features von Programmiersprachen zu implementieren, das 106 00:09:31,850 --> 00:09:35,749 werden wir gleich noch sehen. Wenn jetzt also so ein Programm abläuft, also links 107 00:09:35,749 --> 00:09:39,970 sieht man einen Ausschnitt aus dem Programmspeicher. Also ich habe da jetzt 108 00:09:39,970 --> 00:09:43,759 byteweise mal irgendwelche random Zahlen hingemalt. Naja es sind keine 109 00:09:43,759 --> 00:09:47,670 random Zahlen, es ist tatsächlich ein Teil eines Shell-Codes. Also von dem Ding, was 110 00:09:47,670 --> 00:09:52,259 ich gleich benutze, um meinen Rechner aufzumachen. Die sind jetzt von oben nach 111 00:09:52,259 --> 00:09:56,009 unten byteweise aufgelistet und man würde jetzt sehen, also Speicheradressen gehen 112 00:09:56,009 --> 00:09:59,750 jetzt hier von oben nach unten. Das heißt, oben sind die niedrigen Speicheradressen, 113 00:09:59,750 --> 00:10:03,300 unten sind die hohen Speicheradressen. Und die werden einfach der Reihe nach 114 00:10:03,300 --> 00:10:07,329 durchgezählt, jedes Byte hat halt so eine Adresse. Und so weiß der Prozessor genau, 115 00:10:07,329 --> 00:10:11,379 wenn er gesagt bekommt, macht mal hier an der und der Stelle im Programmcode weiter, 116 00:10:11,379 --> 00:10:15,940 dann springt er halt dahin und liest weiter. Und zwar sieht das so aus, da 117 00:10:15,940 --> 00:10:22,259 werden halt Dinge, also dass der Opcode oder der Befehl, der gerade ausgeführt 118 00:10:22,259 --> 00:10:25,389 werden soll, wird eingelesen und wird ausgeführt und der könnte dann zum 119 00:10:25,389 --> 00:10:30,910 Beispiel so etwas machen wie ein Datum aus dem Registersatz in den Stack legen oder 120 00:10:30,910 --> 00:10:34,720 auf den Stack oben drauf legen. Im nächsten Schritt wird dann etwas anderes 121 00:10:34,720 --> 00:10:38,639 oben draufgelegt und dann wird da wieder was runtergeholt und wieder zurück in das 122 00:10:38,639 --> 00:10:41,899 Register geschrieben, möglicherweise noch irgendwomit verrechnet und so, hangelt er 123 00:10:41,899 --> 00:10:48,230 sich halt durch den Code durch. Von oben nach unten. Man sieht auch, es muss nicht 124 00:10:48,230 --> 00:10:54,369 unbedingt immer alles, jedes Ding muss nicht auch ein Befehl sein, da sind auch 125 00:10:54,369 --> 00:10:59,499 Daten dazwischen. In diesem Fall halt das, was auf den Stack gelegt wurde. Aber im 126 00:10:59,499 --> 00:11:02,110 Prinzip funktioniert das so. Ein Rechner geht einfach der Reihe nach die Befehle 127 00:11:02,110 --> 00:11:04,470 durch. Es gibt dann halt auch Sprungbefehle, die sagen können: springe 128 00:11:04,470 --> 00:11:08,790 mal irgendwie zurück oder springe mal vor, aber im Prinzip ist das alles was ein 129 00:11:08,790 --> 00:11:16,660 Rechner macht. Okay, der Shell Code, den ich gleich benutzen werde, sieht so aus. 130 00:11:16,660 --> 00:11:21,660 Das ist offensichtlich ein Programm, was den laufenden Prozess beendet und eine 131 00:11:21,660 --> 00:11:26,929 Shell mit dem Namen "sh" startet. Nun ist das natürlich nicht so offensichtlich, so 132 00:11:26,929 --> 00:11:29,509 will ja keiner Code schreiben. Deswegen haben sich Leute einfallen lassen: Hey, 133 00:11:29,509 --> 00:11:33,930 wir müssen irgendwie es schaffen, was lesbareres zu bekommen und außerdem würden 134 00:11:33,930 --> 00:11:36,499 wir ganz gerne, wenn wir ein Programm geschrieben haben, das nicht für jeden 135 00:11:36,499 --> 00:11:40,249 Prozessor dieser Welt neu schreiben müssen. Weil das da ist Code, der nur auf 136 00:11:40,249 --> 00:11:45,860 diesem Prozessor, in diesem Fall ein x86 Prozessor ,läuft. Wenn ich versuche, den 137 00:11:45,860 --> 00:11:49,399 auf einem ARM-Prozesor laufen zu lassen, dann sagt er: Kenne ich nicht den Befehl, 138 00:11:49,399 --> 00:11:56,309 mache ich nicht. Beides erreicht man mit sogenannten höheren Programmiersprachen. 139 00:11:56,309 --> 00:12:03,350 Eine davon ist C. Das gleiche Programm sieht in C so aus. Und hier kann man schon 140 00:12:03,350 --> 00:12:06,450 einigermaßen erkennen, okay hier ist irgendwie ein String drin, offensichtlich 141 00:12:06,450 --> 00:12:12,879 also eine Zeichenkette die auf /bin/sh zeigt. Das ist für Leute, die Unix kennen, 142 00:12:12,879 --> 00:12:17,739 die Standard Shell. Also ein Kommandozeileninterpreter. Und darunter ist 143 00:12:17,739 --> 00:12:22,660 eine Zeile, naja die ist wirklich sehr kryptisch, die muss man schon kennen. Es 144 00:12:22,660 --> 00:12:26,489 ruft halt das Programm auf. Aber wie gesagt, Menschen, die sich damit ein 145 00:12:26,489 --> 00:12:29,759 bisschen auskennen, die können so etwas direkt auf Anhieb lesen, das da oben 146 00:12:29,759 --> 00:12:35,389 natürlich nicht. Dieser Code wird jetzt in einen sogenannten Compiler reingeschmissen 147 00:12:35,389 --> 00:12:43,069 und der Compiler macht dann aus dem Unteren ungefähr das Obere wieder. Zudem 148 00:12:43,069 --> 00:12:47,129 gibt es dann, wenn man schon so eine schöne Abstraktion hat, noch 149 00:12:47,129 --> 00:12:51,230 Programmbibliotheken, dass man nicht jeden Scheiß neu machen muss. So was wie: öffne 150 00:12:51,230 --> 00:12:55,120 mir eine Datei und lies den Inhalt. Das will ich ja nicht jedes mal auf der Ebene 151 00:12:55,120 --> 00:12:59,989 neu programmieren. Deswegen lege ich mir dafür schöne Bibliotheken an, mit 152 00:12:59,989 --> 00:13:04,920 Funktionen. Funktionen sind Teile also wieder verwertbare Programmteile, die 153 00:13:04,920 --> 00:13:08,829 einen definierten Satz von Eingabeparametern haben. Also ich kann 154 00:13:08,829 --> 00:13:13,579 einer Datei-öffnen-Funktionen beispielsweise mitgeben, wo die Datei sich 155 00:13:13,579 --> 00:13:16,929 befindet im Dateisystem und ob ich sie lesend schreiben (öffnen) möchte oder schreibend 156 00:13:16,929 --> 00:13:23,480 oder beides. Dann haben die einen Funktionsrumpf. Das ist der Teil der 157 00:13:23,480 --> 00:13:27,259 Funktionen, der was macht. Der also das tut, was die Funktion tun soll mit den 158 00:13:27,259 --> 00:13:31,259 Eingangsparametern und dann gibt es noch einen Return-Wert, dass ist also ein 159 00:13:31,259 --> 00:13:34,129 Rückgabewert, den die Funktion dann zurück gibt, wenn sie fertig ist mit was immer 160 00:13:34,129 --> 00:13:38,860 sie getan hat. Und auf diese Weise baut man sich halt Bibliotheken und verwendet 161 00:13:38,860 --> 00:13:41,929 die halt immer wieder. Dieses execve ganz unten ist beispielsweise eine 162 00:13:41,929 --> 00:13:47,799 Bibliotheksfunktion. Und das war im Prinzip schon alles, was wir für den 163 00:13:47,799 --> 00:13:59,829 Exploit wissen müssen. Wenn nämlich jetzt so eine Funktionen aufgerufen wird. Nehmen 164 00:13:59,829 --> 00:14:05,639 wir mal an, wir hätten eine Funktion, die drei Parameter hat, einer davon ist, ach 165 00:14:05,639 --> 00:14:09,509 Quatsch. Zwei Parameter hat, entschuldigung, und drei lokale Variablen. 166 00:14:09,509 --> 00:14:13,379 Achso, Variable habe ich gar nicht erklärt. Variablen ist auch ein Konzept 167 00:14:13,379 --> 00:14:17,970 von Programmiersprachen. Da kann ich halt Speicheradressen sprechende Namen geben. 168 00:14:17,970 --> 00:14:24,329 Dass ich halt als Programmierer sehen kann, wo ich was abgelegt habe. Und Funktionen 169 00:14:24,329 --> 00:14:29,160 können lokale Variablen haben. Davon beliebig viele und die werden eben über 170 00:14:29,160 --> 00:14:32,350 einen Stack abgebildet, genauso wie die Funktionsparameter über einen Stack 171 00:14:32,350 --> 00:14:36,399 abgebildet werden und der Rückgabewert weiß ich jetzt gerade nicht, da will ich 172 00:14:36,399 --> 00:14:40,699 nichts falsches sagen. Könnte sein, dass der auch über einen Stack läuft, bin ich 173 00:14:40,699 --> 00:14:45,160 mir aber gerade nicht sicher. Nein, ich glaube, läuft er nicht, whatever. Wenn ich 174 00:14:45,160 --> 00:14:48,509 jetzt mir eine Funktion vorstelle, die zwei Parameter hat und drei lokale 175 00:14:48,509 --> 00:14:54,860 Variablen. Davon soll eine ein Buffer sein, dann passiert, wenn die Funktion 176 00:14:54,860 --> 00:14:59,769 aufgerufen wird, folgendes: Zuerst werden die Funktionsargumente oder Parameter auf 177 00:14:59,769 --> 00:15:06,009 den Stack gelegt, und zwar in umgekehrter Reihenfolge. Fragt nicht, ist so. Danach 178 00:15:06,009 --> 00:15:10,589 wird die momentane Adresse oder die nächste Adresse auf den Stack gelegt, 179 00:15:10,589 --> 00:15:15,220 damit das Programm weiß, wenn es aus der Funktion zurückkommt, wo es weitermachen 180 00:15:15,220 --> 00:15:21,419 muss, weil es folgt ja ein Sprung. Dann kommt noch was, das uns nicht interessiert 181 00:15:21,419 --> 00:15:26,689 und dann kommen die lokalen Variablen der Funktion selber. In diesem Fall eine 182 00:15:26,689 --> 00:15:30,119 Variable, dann kommt ein Buffer und dann kommt noch eine Variable. An dieser Stelle 183 00:15:30,119 --> 00:15:32,333 ist sehr schön zu erklären, was ein Buffer ist. Ein Buffer ist 184 00:15:32,333 --> 00:15:39,489 eigentlich nichts anderes als eine Variable, die aber mehr Speicher hat. 185 00:15:39,489 --> 00:15:44,029 Also das ist jetzt nicht eine Zahl, sondern es sind beispielsweise 512 Zahlen 186 00:15:44,029 --> 00:15:49,720 der gleichen Größe. Das ist ein Buffer. Das hier wäre zum Beispiel jetzt ein 187 00:15:49,720 --> 00:15:56,350 Buffer der Größe 5. 5 Bytes groß. Die können beliebig groß sein, wobei beliebig 188 00:15:56,350 --> 00:16:00,519 ist nicht ganz richtig. Hängt von der Speichergröße ab, wie ich gestern gelernt 189 00:16:00,519 --> 00:16:07,569 habe, bei der Demo. lacht Ja, aber im Prinzip sind die nicht begrenzt und das 190 00:16:07,569 --> 00:16:09,930 Schlimme ist, man muss sich wenn man so low level programmiert, selber darum 191 00:16:09,930 --> 00:16:15,679 kümmern, dass man die Grenzen einhält und nicht zu viel da rein schreibt. Und dann 192 00:16:15,679 --> 00:16:23,089 sind wir schon beim Programm. Das Rechte ist das C Program, was ich exploite. Das 193 00:16:23,089 --> 00:16:28,160 ist relativ überschaubar, oben diese Zeile "int main", das kann man ignorieren, dass 194 00:16:28,160 --> 00:16:32,879 braucht man halt, um C zu sagen: hier beginnt das Programm, hier geht es los und 195 00:16:32,879 --> 00:16:37,529 es ist aber wichtig zu wissen, dass main bereits eine Funktion ist. Also vorher 196 00:16:37,529 --> 00:16:44,419 passieren noch andere Dinge, die wir nicht genauer betrachten, die mir aber sehr 197 00:16:44,419 --> 00:16:49,119 viele Steine in den Weg gelegt haben gestern. lacht Die rufen am Ende dann 198 00:16:49,119 --> 00:16:55,209 halt diese Funktion main auf. Es ist also ein ganz normaler Funktionsaufruf. Die 199 00:16:55,209 --> 00:16:58,239 Funktion main hat jetzt eine lokale Variable, nämlich den Buffer der Größe 200 00:16:58,239 --> 00:17:02,279 256. Das ist nicht mehr ganz aktuell, in der Demo, die ich gleich zeige, ist er ein 201 00:17:02,279 --> 00:17:07,620 bisschen größer, spielt aber keine Rolle. Danach gibt es eine Bibliotheksfunktion 202 00:17:07,620 --> 00:17:15,420 string copy, strcpy. Die kopiert, was immer in argv[1] liegt. Da muss man jetzt 203 00:17:15,420 --> 00:17:20,079 dazu sagen, das ist ein Kommandozeilenparameter. Wenn ich ein 204 00:17:20,079 --> 00:17:23,250 Programm aufrufe auf der Kommandozeile, kann ich dem noch Argumente mitgeben und 205 00:17:23,250 --> 00:17:27,289 das erste Argument, was ich dem mitgebe in diesem Fall, würde halt in den Buffer 206 00:17:27,289 --> 00:17:33,840 kopiert. Danach wird eine nette Nachricht ausgegeben "Hallo, was immer in dem Buffer 207 00:17:33,840 --> 00:17:38,520 steht" und dann folgt das return. Sprich, die Funktionen kehrt zurück und dieser 208 00:17:38,520 --> 00:17:43,130 ganze Stack wird abgeräumt und der Prozessor springt dahin, an die Stelle, 209 00:17:43,130 --> 00:17:48,110 deren Adresse jetzt in return links rot markiert steht. Also weil vorher hat sich 210 00:17:48,110 --> 00:17:51,620 ja das Programm gemerkt, wo es nachher hin zurück muss, indem es die Adresse extra da 211 00:17:51,620 --> 00:17:56,470 hingelegt hat. Und wenn ich jetzt zu viele Daten in diesen Buffer rein schreibe, der 212 00:17:56,470 --> 00:18:01,039 ist links verkürzt dargestellt, also jetzt die letzten 5 Bytes von diesem 256 213 00:18:01,039 --> 00:18:05,519 Bytes Buffer, wenn ich jetzt zu viele Daten da reinschreibe, dann kommt 214 00:18:05,519 --> 00:18:10,080 irgendwann der Punkt, wo ich halt die letzten paar Bytes überschreibe. Dann 215 00:18:10,080 --> 00:18:13,000 überschreibe ich das Ding, was uns nicht interessiert und irgendwann überschreibe 216 00:18:13,000 --> 00:18:19,149 ich die Return-Adresse. Was jetzt passiert, erst mal noch nichts. Dann kommt 217 00:18:19,149 --> 00:18:26,350 das return 0 und was das return macht: Es lädt was immer an dieser stelle steht 218 00:18:26,350 --> 00:18:29,669 zurück in den instruction pointer, also an die Stelle, wo sich der Prozessor intern 219 00:18:29,669 --> 00:18:34,880 merkt, wo das Programm gerade steht und macht an der Stelle weiter. Wenn ich es 220 00:18:34,880 --> 00:18:41,820 jetzt schaffe, in diesen Buffer meinen Shell Code reinzuladen, also das kleine 221 00:18:41,820 --> 00:18:45,810 Programmstück, was ihr eben gesehen habt, was das laufende Programm beendet und ein 222 00:18:45,810 --> 00:18:49,230 neues Programm, nämlich einen Kommandozeileninterpreter startet, wenn 223 00:18:49,230 --> 00:18:53,060 ich das jetzt schaffe das da oben rein zu schreiben und zudem noch es schaffe, an 224 00:18:53,060 --> 00:19:00,429 die Return-Adresse den Anfang von diesem Code reinzuschreiben, dann passiert genau, 225 00:19:00,429 --> 00:19:04,280 was nicht passieren darf: Nämlich das Programm macht, was ich ihm vorher gesagt 226 00:19:04,280 --> 00:19:10,620 habe und was ich vorher in diesem Buffer reingeschrieben habe. Und jetzt kommt der 227 00:19:10,620 --> 00:19:16,130 Punkt, an dem es interessant wird. Jetzt muss ich erst mal meine Maus wiederfinden, 228 00:19:16,130 --> 00:19:41,529 dass habe ich mir alles anders vorgestellt. Sieht man das? Das ist ein 229 00:19:41,529 --> 00:19:57,440 bisschen klein. Könnt ihr das lesen, nein oder? Da hinten, könnt ihr 230 00:19:57,440 --> 00:20:05,570 das da hinten lesen? Nein. Bis gerade eben konnte ich auch noch die Größe von meinem 231 00:20:05,570 --> 00:20:15,070 Terminal verstellen. Das scheint jetzt nicht mehr zu gehen. Aha, geht nur auf dem 232 00:20:15,070 --> 00:20:26,139 linken Bildschirm, aus Gründen! Könnt ihr das jetzt einigermaßen lesen? Gut. Also 233 00:20:26,139 --> 00:20:36,639 ich habe hier dieses Programm, ich habe das mal vorbereitet. Es macht, was es 234 00:20:36,639 --> 00:20:40,500 soll, es liest halt den ersten Parameter ein, also "vuln" ist das Programm, das 235 00:20:40,500 --> 00:20:44,129 verwundbar ist. Ich habe ihm den Parameter "haggl" mit gegeben, also sagt das "Hallo, 236 00:20:44,129 --> 00:20:49,740 haggl", alles cool. Wenn ich jetzt aber Dinge da rein schreibe, die ein bisschen 237 00:20:49,740 --> 00:21:09,529 länger sind, beispielsweise so etwas. Ich hoffe, das ist die richtige Syntax um in 238 00:21:09,529 --> 00:21:14,669 Python Dinge auf der Kommandozeile direkt auszuführen. Ja. Dann kriege ich einen 239 00:21:14,669 --> 00:21:18,179 segmentation fault. Ein segmentation fault ist der nette Hinweis vom 240 00:21:18,179 --> 00:21:22,360 Betriebssystemen: Kollege, du hast gerade Speicher lesen und/oder schreiben wollen, 241 00:21:22,360 --> 00:21:29,750 auf den du keinen Zugriff hast. Wenn Leute die Exploits schreiben, so etwas kriegen, 242 00:21:29,750 --> 00:21:33,360 also das ist das was normalerweise das kennt wahrscheinlich jeder, was passiert 243 00:21:33,360 --> 00:21:36,190 wenn ein Programm einfach so ohne irgendetwas zu sagen abstürzt, dann ist 244 00:21:36,190 --> 00:21:40,809 das oft ein segmentation fault. Das ist für die meisten Menschen sehr nervig, weil 245 00:21:40,809 --> 00:21:43,460 man dann das Programm neu starten muss, gegebenenfalls Daten verloren gegangen 246 00:21:43,460 --> 00:21:47,600 sind. für Leute, die Exploits schreiben, ist das der heilige Gral, weil 247 00:21:47,600 --> 00:21:52,770 segmentation faults sind oft ein Indiz dafür, dass es da gerade einen Buffer 248 00:21:52,770 --> 00:21:56,200 Overflow gegeben hat. Und ein Buffer Overflow, damit kann man eine Menge 249 00:21:56,200 --> 00:22:10,760 anfangen. Man kann beispielsweise einen Shell Code reinladen. xxd -p shellcode, 250 00:22:10,760 --> 00:22:15,539 das ist das Ding, was wir eben in den Slides gesehen haben. Das ist also dieses 251 00:22:15,539 --> 00:22:21,840 Programm in Maschinencode, was das laufende Programm beendet und eine Shell 252 00:22:21,840 --> 00:22:29,780 startet. Und wenn ich die jetzt da rein injecte, also anstatt jetzt diesem 253 00:22:29,780 --> 00:22:39,150 Pythonding oder dem einfachen String haggl, dieses Teil jetzt da rein pipe, 254 00:22:39,150 --> 00:22:44,380 dann bekomme ich eine Shell. Und zwar eine Shell, die nicht die andere Shell ist, 255 00:22:44,380 --> 00:22:50,120 sondern eine neue Shell ist. An der Stelle habe ich es geschafft. Jetzt bin ich halt 256 00:22:50,120 --> 00:22:55,730 drin und kann hier auf dem System beliebige Dinge machen. Das ist erstmal so 257 00:22:55,730 --> 00:23:01,320 noch nicht so schlimm und das ist ja auch ein sehr akademisches Beispiel, weil ich 258 00:23:01,320 --> 00:23:03,860 es alles selber geschrieben habe. Ich muss auf dem eigenen Rechner sein, ich bin eh 259 00:23:03,860 --> 00:23:08,330 schon der Benutzer, aber interessant wird es natürlich, wenn so eine Verwundbarkeit 260 00:23:08,330 --> 00:23:11,920 irgendwo an der Stelle sitzt, die auf das Netzwerk horcht. Wenn man von außen 261 00:23:11,920 --> 00:23:16,529 irgendwie Pakete einschleusen kann, die so etwas hervorrufen. Und ich dann irgendwie 262 00:23:16,529 --> 00:23:20,340 eine Shell oder ähnliches bekomme. Auch interessant wird es, wenn das ein Dienst 263 00:23:20,340 --> 00:23:24,070 ist, der aus Gründen mit root-Rechten laufen muss. Dann habe ich nämlich auf 264 00:23:24,070 --> 00:23:28,690 einmal eine root-Shell. Und so weiter und so fort. Also man kann da eine Menge 265 00:23:28,690 --> 00:23:36,110 lustige Sachen mit machen. Ich habe noch etwas anderes vorbereitet. Und zwar, wenn 266 00:23:36,110 --> 00:23:40,050 ich jetzt einen Debugger über das Ding laufen lassen. Ein Debugger ist ein 267 00:23:40,050 --> 00:23:45,340 Programm, mit dem ich zur Laufzeit rein gucken kann, in den Speicher, und schauen 268 00:23:45,340 --> 00:23:49,019 kann, was denn der Prozess so gerade da macht, und was wo an welcher Stelle im 269 00:23:49,019 --> 00:23:53,410 Speicher geschrieben wird. Hier sehe ich jetzt noch mal den Quellcode von dem 270 00:23:53,410 --> 00:23:56,310 Programm. Das ist das gleiche wie eben, bis auf das der Buffer ein bisschen größer 271 00:23:56,310 --> 00:24:03,510 ist. Das spielt aber keine große Rolle und ich habe zwei breakpoints gesetzt. 272 00:24:03,510 --> 00:24:07,049 Breakpoint heißt, das Programm oder der Debugger vielmehr, hält das Programm an 273 00:24:07,049 --> 00:24:12,550 der Stelle an, damit man halt schauen kann, was an bestimmten Speicheradressen 274 00:24:12,550 --> 00:24:18,440 steht. Und einer ist hier auf dieser Zeile stringcopy, Zeile 6. Also der macht, hält 275 00:24:18,440 --> 00:24:23,809 an bevor das reinkopiert wurde, und der nächste breakpoint hält kurz vor dem 276 00:24:23,809 --> 00:24:27,240 return an. Und da müsste ich halt dann schon sehen, was im Buffer passiert ist. 277 00:24:27,240 --> 00:24:31,759 Wenn ich das Programm jetzt laufen lasse, mit den richtigen Argumenten, das ist 278 00:24:31,759 --> 00:24:36,360 alles schon hoffentlich konfiguriert, ja, dann sehe ich hier, das es ist ein 279 00:24:36,360 --> 00:24:40,090 Ausschnitt aus dem Buffer, und zwar die letzten, irgendwo in den letzten paar 280 00:24:40,090 --> 00:24:45,249 hundert Bytes, da steht ziemlich zufälliger Quatsch drin. Keine Ahnung, was 281 00:24:45,249 --> 00:24:50,259 das ist das. Das hat irgend ein Prozess vorher, oder vielleicht möglicherweise 282 00:24:50,259 --> 00:24:56,169 auch der init Prozess, also das was vor meinem eigentlichen main Programm läuft, 283 00:24:56,169 --> 00:25:02,929 da hingelegt, keine Ahnung, weiß ich nicht. Und die return Adresse steht im 284 00:25:02,929 --> 00:25:07,090 Moment noch auf dieser lustigen, kryptischen Zahl. Das wird irgendwas sein, 285 00:25:07,090 --> 00:25:11,700 was, nachdem main beendet wurde, also die Funktion main beendet wurde, 286 00:25:11,700 --> 00:25:18,361 wahrscheinlich noch irgendwie Speicher aufräumt oder so etwas. So, jetzt sind wir 287 00:25:18,361 --> 00:25:22,500 also an der Stelle stringcopy, also es ist noch nichts passiert. Wenn ich jetzt zum 288 00:25:22,500 --> 00:25:31,460 nächsten breakpoint weiterlaufe, dann seht ihr? Hier oben sind ganz viele 0x90 289 00:25:31,460 --> 00:25:35,071 Instruktionen. Das sind die Anweisungen für den Prozessor: mach mal nichts, warte 290 00:25:35,071 --> 00:25:39,929 mal einen Takt lang. Und davon habe ich ganz viele da rein geschrieben und 291 00:25:39,929 --> 00:25:45,409 irgendwann kommt dann hier dieser Shell Code. Das war das Ding, was eben das 292 00:25:45,409 --> 00:25:50,710 Programm beendet und die Shell startet. Und ich kann auch schon sehen, die return 293 00:25:50,710 --> 00:25:53,870 Adresse ist jetzt überschrieben worden mit einer Adresse, die ich selber gewählt 294 00:25:53,870 --> 00:25:59,211 habe. Und diese Adresse, die zielt irgendwo oben vor den Shell Code in diese 295 00:25:59,211 --> 00:26:04,770 ganzen no-operation Instruktionen, das nennt man eine NOP-slide. Das macht man, 296 00:26:04,770 --> 00:26:07,460 um ein bisschen zu puffern und ein bisschen Platz zu haben und ein bisschen 297 00:26:07,460 --> 00:26:10,779 Freiheit zu haben, weil wenn so ein Prozess gestartet wird, dann hängen da 298 00:26:10,779 --> 00:26:16,450 oben über dem Stack noch ganz viele andere Sachen und die können sich, nicht zur 299 00:26:16,450 --> 00:26:19,149 Laufzeit, die können sich aber auch von Programmausführung zu Programmausführung 300 00:26:19,149 --> 00:26:23,779 ändern. Wenn ich zum Beispiel eine neue Variable definiere oder whatever. 301 00:26:23,779 --> 00:26:26,629 Jedenfalls habe ich die Sachen nicht immer exakt an der gleichen Speicheradresse und 302 00:26:26,629 --> 00:26:29,260 deswegen macht man gerne so einen NOP- slide. Also man nimmt seinen Shell Code, 303 00:26:29,260 --> 00:26:32,720 packt den irgendwo in die Mitte, packt davor ganz viele NOPs, wo der Rechner 304 00:26:32,720 --> 00:26:35,389 einfach so durchtingelt und nichts tut, und dann irgendwann an dem Shell Code 305 00:26:35,389 --> 00:26:39,400 ankommt und dahinter packt man ganz viele return Adressen, die oben in diese NOP- 306 00:26:39,400 --> 00:26:44,850 Slide reinspringen. Das heißt, egal ob ich den Bereich vor dem Shell Code treffe oder 307 00:26:44,850 --> 00:26:47,870 den Bereich hinter dem Shell Code treffe, es passiert immer was passieren muss, 308 00:26:47,870 --> 00:26:52,110 nämlich er springt im ungünstigsten Fall von hinterm Shell Code zu vor dem Shell 309 00:26:52,110 --> 00:26:55,960 Code und hangelt sich dann durch bis zum Shell Code, der dann das tut, was er tut. 310 00:26:55,960 --> 00:27:08,669 Und das ist der Buffer Overflow Exploit. Demo Time! Ja wobei, wie ich schon sagte, 311 00:27:08,669 --> 00:27:12,620 das ist ein sehr akademisches Beispiel, weil ich das alles halt sehr, um es 312 00:27:12,620 --> 00:27:18,750 einfach zu halten, sehr klein gehalten habe. In der Realität würde man sagen, es 313 00:27:18,750 --> 00:27:22,081 ist ja keiner so blöd, wenn da irgendwas in den Puffer rein schreibt, nicht zu 314 00:27:22,081 --> 00:27:25,049 checken, wie groß denn der Puffer ist und mal zu gucken, ob man überhaupt noch da 315 00:27:25,049 --> 00:27:33,639 rein schreiben darf. Das stimmt auch, meistens. lacht Das Problem ist: selbst, 316 00:27:33,639 --> 00:27:38,340 wenn es immer gemacht würde, habe ich oft das Problem, dass ich das zu der Zeit, wo 317 00:27:38,340 --> 00:27:40,929 ich das Programm schreibe, noch gar nicht wissen kann, wie groß dieser Buffer sein 318 00:27:40,929 --> 00:27:43,950 muss, weil ich es erst zur Laufzeit mitbekomme, wie viele Pakete da jetzt 319 00:27:43,950 --> 00:27:47,769 gleich ankommen, wenn es zum Beispiel ein Netzwerkdienst ist. Das heißt, die Größe 320 00:27:47,769 --> 00:27:50,799 von so einem Buffer wird oft berechnet und wenn ich jetzt bei der Berechnung der 321 00:27:50,799 --> 00:27:53,881 Größe irgend einen Fehler habe, der dazu führt, dass ich eine falsche Größe raus 322 00:27:53,881 --> 00:27:58,139 bekomme, die dann dazu führt, dass der Rechner, oder das Programm vielmehr, 323 00:27:58,139 --> 00:28:03,260 denkt, der Buffer ist riesig groß, dann schreibt das Ding halt weiter. Das ist 324 00:28:03,260 --> 00:28:12,340 eine Sache, die oft ausgenutzt wird und Daten kommen halt eben, let's face it, 325 00:28:12,340 --> 00:28:18,389 meistens nicht von der Kommandozeile, aber stattdessen kommen die aus Dateien, die 326 00:28:18,389 --> 00:28:22,539 ich irgendwie manipulieren kann oder sogar aus dem Netzwerk. Da habe ich natürlich 327 00:28:22,539 --> 00:28:28,259 dann beliebige Angriffsvektoren. Das heißt, was in der Realität passieren 328 00:28:28,259 --> 00:28:32,910 würde, also jetzt beispielsweise bei diesen drei Dingern die wir da hatten: Das 329 00:28:32,910 --> 00:28:40,119 Erste war ja der Firefox Browser. Da würde man vermutlich ein Bild beispielsweise 330 00:28:40,119 --> 00:28:45,139 sich zusammen bauen, was irgendwie den Bild Standard nicht ganz erfüllt oder wo 331 00:28:45,139 --> 00:28:52,880 irgendwo ein Byte falsch ist, so dass, wenn der Browser das Bild lädt, sich irgendwo 332 00:28:52,880 --> 00:28:57,220 verhaspelt und irgendwo es zu einem Buffer Overflow kommt, weil z. B. ein Puffer zu 333 00:28:57,220 --> 00:29:02,650 klein ausgelegt wird. Oder ich kann versuchen, es über Javascript Dinge zu 334 00:29:02,650 --> 00:29:07,679 machen, aber das ist eigentlich noch was anderes. Im zweiten Fall, von dem Adobe 335 00:29:07,679 --> 00:29:12,659 Reader, sind es auch oft tatsächlich irgendwelche Bilder. Das Problem bei dem 336 00:29:12,659 --> 00:29:15,850 Adobe Reader ist halt so ein bisschen das der so eine eierlegende Wollmilchsau ist. 337 00:29:15,850 --> 00:29:22,140 Ich kann mit dem Teil ja beliebige Bildformate anzeigen lassen, Text mit 338 00:29:22,140 --> 00:29:25,509 eigenen Schriften, dass wäre auch ein Angriffsvektor, wenn ich da eine eigene 339 00:29:25,509 --> 00:29:28,789 Schrift einbauen und die Schrift halt irgendwie so baue, dass beim Einlesen und 340 00:29:28,789 --> 00:29:33,970 beim Parsen und Bauen dieser Schrift der Reader irgendwie einen Buffer Overflow 341 00:29:33,970 --> 00:29:39,889 kriegt. Bis hin zu 3D Elemente, ich habe gehört, sie haben teile von Flash in den 342 00:29:39,889 --> 00:29:45,350 Adobe Reader eingebaut, damit man damit dann 3D Modelle irgendwie anzeigen und 343 00:29:45,350 --> 00:29:50,299 auch schön drehen kann. Was man ja alles braucht, alles im gleichen Programm, gute 344 00:29:50,299 --> 00:29:55,309 Idee! Naja jedenfalls, auch da bieten sich verschiedenste Angriffsvektoren und was 345 00:29:55,309 --> 00:30:00,940 man machen würde ist halt eine Datei bauen, die halten den Fehler ausnutzt und 346 00:30:00,940 --> 00:30:07,510 einen Buffer Overflow erzeugt. Der Angriff den ich hier gezeigt habe, der ist heute 347 00:30:07,510 --> 00:30:11,919 aus verschiedenen Gründen nicht mehr möglich. Ich musste drei Dinge abschalten 348 00:30:11,919 --> 00:30:16,220 um den überhaupt laufen lassen zu können. Das Eine ist, wie ihr euch wahrscheinlich 349 00:30:16,220 --> 00:30:19,340 jetzt schon gedacht habt, naja dann könnte ich doch einfach sagen ich habe einen 350 00:30:19,340 --> 00:30:22,879 bestimmten Programmspeicher, ich habe einen bestimmten Datenspeicher und was im 351 00:30:22,879 --> 00:30:26,480 Datenspeicher liegt, darf niemals nicht vom Prozessor ausgeführt werden. Das gibt es. 352 00:30:26,480 --> 00:30:31,779 Das nennt sich "write XOR execute" und ist seit einigen Jahren im Kernel und sogar in 353 00:30:31,779 --> 00:30:36,710 Hardware drin. Wenn es angeschaltet ist. Das musste ich ausschalten, dann gibt es 354 00:30:36,710 --> 00:30:41,580 noch die Möglichkeit sogenannte Stack Canaries, also Kanarienvögel, in den Stack 355 00:30:41,580 --> 00:30:46,919 einzubauen. Das ist so ein Magic Byte, was da reingeschrieben wird, und ein bisschen 356 00:30:46,919 --> 00:30:50,669 Code, was vor dem rückkehren der Funktion noch einmal testet, ob dieses Byte, was 357 00:30:50,669 --> 00:30:57,100 ich da reingeschrieben habe, also zwischen den lokalen Variablen und der 358 00:30:57,100 --> 00:31:01,499 Returnadresse, moment ich mache das mal eben grafisch, damit man das sehen kann, 359 00:31:01,499 --> 00:31:05,070 genau, also an diese Stelle, die jetzt da schwarz markiert ist, zwischen dem Return 360 00:31:05,070 --> 00:31:10,149 und dem Buffer, würde man ein zur Laufzeit gewähltes beliebiges Byte reinschreiben 361 00:31:10,149 --> 00:31:14,419 und bevor man aus der Funktion zurückkehrt, würde man testen, ob dieses 362 00:31:14,419 --> 00:31:18,690 Byte, was man da vorher reingeschrieben hat, noch das gleiche ist wie vorher. Wenn 363 00:31:18,690 --> 00:31:21,090 nicht, ist ein Buffer Overflow passiert und dann lässt man das Programm besser 364 00:31:21,090 --> 00:31:26,239 sofort abstürzen, anstatt abzuwarten, was jetzt kommt. Das ist ein Stack Canary. 365 00:31:26,239 --> 00:31:33,040 Auch das musste ich ausschalten. Und das Dritte ist bei modernen Betriebssystemen, 366 00:31:33,040 --> 00:31:35,690 mittlerweile haben es glaube ich alle drin, ist das so, dass jeder Prozess mit 367 00:31:35,690 --> 00:31:42,509 einem zufälligen Speicherlayout läuft. Das heißt, ich kann nicht mehr wirklich sagen 368 00:31:42,509 --> 00:31:46,360 wo meine Dinge im Speicher liegen und das macht es sehr sehr schwierig, weil ich ja 369 00:31:46,360 --> 00:31:51,619 irgendwo an den Shell Code, an das Ende vom Shell Code, eine Adresse schreiben 370 00:31:51,619 --> 00:31:55,960 muss, die vorne in diese NOP slide reinführt. Und wenn ich absolut keine 371 00:31:55,960 --> 00:31:59,009 Ahnung habe, wo diese Adresse ist, also ich kann nicht mehr durch Vergrößern des 372 00:31:59,009 --> 00:32:02,179 Buffers oder durch mehr NOPs einfügen kann ich das irgendwann nicht mehr schaffen, 373 00:32:02,179 --> 00:32:06,330 weil es einfach so zufällig ist, dass ich keine Chance mehr habe herauszufinden, wo 374 00:32:06,330 --> 00:32:10,889 zur Laufzeit denn dieser Shell Code liegt, und wenn ich nicht weiß wo der liegt, kann 375 00:32:10,889 --> 00:32:15,399 ich da nicht rein springen, kann ich also keinen Buffer Overflow Exploit machen. 376 00:32:15,399 --> 00:32:19,080 Diese drei Dinge gibt es heute, die sind in der Regel, also zwei davon macht der 377 00:32:19,080 --> 00:32:23,049 Compiler, das Dritte macht das Betriebssystem, und die musste ich jetzt 378 00:32:23,049 --> 00:32:27,369 alle umgehen, um das überhaupt demonstrieren zu können. Aber die zugrunde 379 00:32:27,369 --> 00:32:32,049 liegenden Probleme bestehen weiterhin, die sind nämlich: Speichermanagement ist 380 00:32:32,049 --> 00:32:36,570 fehleranfällig, Menschen machen immer Fehler, ist oft auch nicht so 381 00:32:36,570 --> 00:32:41,149 übersichtlich, Datenformate sind zu komplex, Programme müssen zu viel 382 00:32:41,149 --> 00:32:45,679 gleichzeitig können und das führt alles dazu, dass halt immer mehr Fehler 383 00:32:45,679 --> 00:32:48,649 passieren. Je höher die Komplexität ist, desto höher ist natürlich die 384 00:32:48,649 --> 00:32:53,629 Wahrscheinlichkeit, das ich Fehler mache. Und das ist nicht gefixt und die 385 00:32:53,629 --> 00:32:58,460 Programmiersprachen, die man dafür verwendet, sind eigentlich einer Zeit 386 00:32:58,460 --> 00:33:03,639 entstammend, in der das Internet noch ein freundlicher Ort war. Man kannte sich und 387 00:33:03,639 --> 00:33:09,100 da hat man über Security nicht so richtig nachgedacht. Es gibt außerdem Nachfolger 388 00:33:09,100 --> 00:33:13,419 von dieser Praxis, also diese Praxis, die ich jetzt hier gezeigt habe, geht halt 389 00:33:13,419 --> 00:33:16,679 nicht, aber es gibt Nachfolger davon, also Modifikationen davon, die sind ein 390 00:33:16,679 --> 00:33:20,350 bisschen gewiefter, ein bisschen trickreicher und die schaffen es dann, 391 00:33:20,350 --> 00:33:23,760 unter Umständen eben doch noch so etwas nicht zu bekommen. Also das funktioniert 392 00:33:23,760 --> 00:33:30,230 heute immer noch, wie ihr halt an den Nachrichten gesehen habt. Oft werden auch 393 00:33:30,230 --> 00:33:37,519 nicht alle Gegenmaßnahmen ergriffen, das ist halt Teil der Betriebssystemhersteller 394 00:33:37,519 --> 00:33:43,799 bzw. Benutzer. An der Stelle danke ich und Fragen? 395 00:33:43,799 --> 00:33:53,259 Applaus 396 00:33:53,259 --> 00:34:01,999 Herald: Herzlichen Dank haggl für diesen wundervollen Vortrag! So, Frage-Antwort- 397 00:34:01,999 --> 00:34:07,580 Runde, es gibt zwei Mikrofone, die sind dort und dort, beleuchtet, wer eine Frage 398 00:34:07,580 --> 00:34:15,349 hat, stellt sich bitte hinter die Mikrofone und ich rufe dann auf. Keine 399 00:34:15,349 --> 00:34:24,600 Fragen? Das scheint ein ganz schön umfangreicher Vortrag gewesen zu sein. 400 00:34:24,600 --> 00:34:30,210 Haggl: Keine Fragen, oder seid ihr bedient? Keine Fragen, weil es zu viele 401 00:34:30,210 --> 00:34:38,109 gäbe, oder keine Fragen, weil es gar keine mehr gibt? Achso, eine Entweder-Oder-Frage 402 00:34:38,109 --> 00:34:41,800 kann man nicht mit Handzeichen beantworten, das ist schwierig. lacht 403 00:34:41,800 --> 00:34:46,310 Herald: Dort steht jemand, bitte. Frage: Ich hätte mal eine Frage und zwar: 404 00:34:46,310 --> 00:34:51,139 Ich habe die Stelle nicht gefunden, wo die Return-Adresse ausgerechnet wird und 405 00:34:51,139 --> 00:34:54,210 reingeschrieben wird, also der Return- Wert. 406 00:34:54,210 --> 00:34:57,369 Haggl: Ja, die konntest du auch nicht finden, weil ich die garnicht gezeigt 407 00:34:57,369 --> 00:35:16,890 habe. Ich habe dazu noch ein kleines Pythonskript, das das alles macht. Das ist 408 00:35:16,890 --> 00:35:21,381 diese hier. Also der der Shellcode, den ich vorher gezeigt habe, das ist wirklich 409 00:35:21,381 --> 00:35:28,569 nur der Part, der halt execve aufruft mit /bin/sh und der wird halt hier eingelesen 410 00:35:28,569 --> 00:35:33,350 in diesem Pythonskript und dann baue ich mit dem Pythonskript halt eben ganz viele 411 00:35:33,350 --> 00:35:37,250 NOPs davor, das ist an der Stelle, also hier berechne ich erstmal wie lange diese 412 00:35:37,250 --> 00:35:41,250 NOP-slide sein soll und packe halt den NOP-slide davor, dann kommt noch ein 413 00:35:41,250 --> 00:35:45,010 bisschen Padding und Alignment, damit das alles richtig hinten rauskommt, dass 414 00:35:45,010 --> 00:35:50,819 die Rücksprungadresse auch an der richtigen Stelle liegt im stack. Genau und 415 00:35:50,819 --> 00:35:55,511 hier oben habe ich halt diese Target- Adresse und die kriegst du halt nur raus, 416 00:35:55,511 --> 00:35:58,230 wenn du das Programm einmal laufen lässt und mit dem Debugger schaust, na wo ist 417 00:35:58,230 --> 00:36:02,180 denn der Buffer. Und dann kannst du halt irgendwie eine Adresse in der Mitte von 418 00:36:02,180 --> 00:36:07,849 dem Buffer aussuchen, den Shellcode dahinter packen, ein par NOPs davor, dann 419 00:36:07,849 --> 00:36:13,660 tut es das schon. So weit die Theorie, die Praxis, habe ich schmerzhaft gelernt, ist 420 00:36:13,660 --> 00:36:18,730 ein bisschen komplizierter. Genau, also mehr macht dieses Skript auch nicht, es 421 00:36:18,730 --> 00:36:20,710 nimmt den Shellcode, packt NOPs davor, return-Adresse dahinter, fertig. 422 00:36:20,710 --> 00:36:26,460 Frage: Ist die Adresse eine relative oder eine absolute Adresse? 423 00:36:26,460 --> 00:36:33,410 Haggl: Das ist eine absolute Adresse. Und das ist halt das Ding, an der Stelle 424 00:36:33,410 --> 00:36:37,130 greift halt dieses address space layout randomization, also dieser 425 00:36:37,130 --> 00:36:40,440 Abwehrmechanismus vom Betriebssystem, der dafür sorgt, dass jedes mal, wenn ich das 426 00:36:40,440 --> 00:36:45,470 Programm aufrufe, diese Adresse nicht mehr stimmt. Das kann ich euch demonstrieren. 427 00:36:45,470 --> 00:37:01,960 Wenn ich jetzt dieses Ding, was nämlich der make Befehl macht, weil, wenn ich 428 00:37:01,960 --> 00:37:06,280 dieses make exploit mache, was ich euch eben gezeigt habe, da wird vorher noch mit 429 00:37:06,280 --> 00:37:11,520 diesem Befehl hier für den nächsten Prozess, dieses address space layout 430 00:37:11,520 --> 00:37:16,730 randomization ausgeschaltet. Standardmäßig ist das an im Linux Kernel und wenn ich 431 00:37:16,730 --> 00:37:22,800 das nicht mache, sondern einfach nur das Programm aufrufe und da meine payload 432 00:37:22,800 --> 00:37:31,620 reinschiebe, dann gibt es zwar auch einen segmentation fault, natürlich, aber es 433 00:37:31,620 --> 00:37:38,230 gibt halt, ich kriege halt keine shell. Und das ist genau aus dem Grund, weil der 434 00:37:38,230 --> 00:37:41,829 buffer nicht an der Stelle liegt, wo ich ihn vermutet habe und deswegen meine 435 00:37:41,829 --> 00:37:46,309 Rücksprungadresse irgendwo im Speicher zeigt, da springt er dann hin und, ups, 436 00:37:46,309 --> 00:37:54,020 gibts einen segmentation fault. Die beiden anderen Dinge könnte ich auch noch eben 437 00:37:54,020 --> 00:37:58,550 zeigen, ich weiß nicht, wir haben noch Zeit oder? Die beiden an Dinge könnte ich 438 00:37:58,550 --> 00:38:02,820 eben auch noch zeigen, also was man machen muss, um die beiden anderen 439 00:38:02,820 --> 00:38:06,940 Sicherheitsmechanismen abzuschalten. Da muss man das Programm nämlich mit diesen 440 00:38:06,940 --> 00:38:17,760 beiden "-z execstack", das ist dieses was den Softwarecheck ausschaltet, ob ich 441 00:38:17,760 --> 00:38:23,109 gerade im stack versuche Programme, also generell im Datenspeicher, nein im stack, 442 00:38:23,109 --> 00:38:28,410 versuche, Programme auszuführen. Das muss man ausschalten. Und dann gibt es noch 443 00:38:28,410 --> 00:38:32,119 diesen stack protector, dass ist ein stack canarie, dass wird auch standardmäßig 444 00:38:32,119 --> 00:38:37,590 eingebaut. Muss man also auch explizit ausschalten, um das möglich zu machen. Das 445 00:38:37,590 --> 00:38:41,339 heißt , Programme, die mit modernen compilern und modernen compiler flags 446 00:38:41,339 --> 00:38:45,730 kompiliert wurden, sollten trade mark eigentlich nicht so leicht verwundbar 447 00:38:45,730 --> 00:38:50,450 sein. Und wenn dann noch address space layout randomization dazu kommt, dann ist 448 00:38:50,450 --> 00:38:54,799 das schon relativ gut, da muss man schon echt eine Menge Zeug machen, um dann noch 449 00:38:54,799 --> 00:39:01,710 irgendwie reinzukommen. Aber es geht halt trotzdem. 450 00:39:01,710 --> 00:39:05,750 Herald: Gut ich sehe da drüben an dem Mikrofon noch jemanden, der wartet, bitte. 451 00:39:05,750 --> 00:39:11,960 Frage: Kann man nicht einfach relative Adressen verwenden, um ASLR auszuhebeln 452 00:39:11,960 --> 00:39:17,491 und wenn nein, warum nicht? Haggl: Was meinst du mit relativ, relativ 453 00:39:17,491 --> 00:39:23,410 wozu? Frage: Naja, also ich meine, ah nein, ich 454 00:39:23,410 --> 00:39:30,430 habe es gerafft, okay. Haggl: Aber im Prinzip bist du auf dem 455 00:39:30,430 --> 00:39:35,839 richtigen Weg, also was man halt machen kann, ist, man kann herausfinden, wo die 456 00:39:35,839 --> 00:39:40,940 libc zum Beispiel anfängt. Und wenn ich weiß, wo die libc anfängt, dann weiß ich 457 00:39:40,940 --> 00:39:45,440 auch, wenn ich zudem noch die Version von der libc kenne, die da reingelinkt wurde, 458 00:39:45,440 --> 00:39:50,420 weiß ich dann auch, wo bestimmte Dinge aus der libc im Speicher liegen. Und sobald 459 00:39:50,420 --> 00:39:55,369 ich das habe, kann ich halt dann anfangen, mir wieder Dinge zusammenzubauen. Das geht 460 00:39:55,369 --> 00:39:57,290 aber dann eher in Richtung return oriented programming. 461 00:39:57,290 --> 00:40:06,680 Herald: Gut, sieht aus, als sei die Frage beantwortet, gibt es noch weitere Fragen? 462 00:40:06,680 --> 00:40:10,530 Das scheint nicht der Fall zu sein, aus dem Internet scheint auch keine Frage zu 463 00:40:10,530 --> 00:40:21,480 kommen. Dann würde ich hiermit den Vortrag schließen, herzlichen Dank haggl! 464 00:40:21,480 --> 00:40:27,380 Applaus 465 00:40:27,380 --> 00:40:33,275 35c3 Abspannmusik 466 00:40:33,275 --> 00:40:47,000 Untertitel erstellt von c3subtitles.de im Jahr 2020. Mach mit und hilf uns!