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!