< Return to Video

35C3 ChaosWest - Stack Buffer Overflow Exploits - Wie ein "harmloses" Dokument einen Rechner infizi

  • 0:00 - 0:16
    35C3 Vorspannmusik
  • 0:16 - 0:25
    Herald: Gut dann wollen jetzt beginnen.
    Wer von euch hat schon mal eine E-Mail
  • 0:25 - 0:34
    gekriegt mit einem Anhang? Wer von euch
    hat eine E-Mail bekommen mit einem Anhang
  • 0:34 - 0:40
    von einer euch unbekannten Person? Das
    sind erstaunlich wenige, so 20 Prozent.
  • 0:40 - 0:48
    Wer von euch hat den schon mal aufgemacht?
    3, 4. Wer von euch kennt jemanden, der schon
  • 0:48 - 0:56
    mal einen Anhang aufgemacht hat? Ja
    deutlich mehr. Wer von euch musste die
  • 0:56 - 1:03
    Probleme beseitigen, die dadurch
    entstanden sind? Ja auch so 10 20 Prozent
  • 1:03 - 1:12
    würde ich sagen. Ja es ist natürlich eine
    ganz gute Idee, sich zu überlegen, ob man
  • 1:12 - 1:16
    denn jetzt eine Rechnung oder ein Angebot
    auf machen möchte, was man von einer
  • 1:16 - 1:23
    völlig unbekannten Person aus dem Internet
    bekommen hat. Und was da passiert, wenn
  • 1:23 - 1:27
    man es tatsächlich täte, das wird uns
    jetzt haggl erläutern. Applaus.
  • 1:27 - 1:31
    Applaus
  • 1:31 - 1:46
    Haggl: Was? Das sollte so nicht aussehen,
    Moment, warum sagt mir das keiner?
  • 1:46 - 2:16
    So, hallo, dann können wir jetzt ja anfangen.
    Ja also danke für die schöne Einleitung.
  • 2:16 - 2:21
    Schön, dass ihr alle da seid, dass ihr so
    zahlreich erschienen seid. Wie in jedem
  • 2:21 - 2:27
    Jahr eigentlich, gab es auch in 2018 - ich
    schiebe mal eben die Maus da weg - 2018
  • 2:27 - 2:31
    wieder ein paar schöne Beispiele, oder
    schön ist in Anführungszeichen zu setzen,
  • 2:31 - 2:34
    Beispiele von Sicherheitslücken, die
    ziemlich gravierend sind und die
  • 2:34 - 2:40
    geschlossen werden, glücklicherweise,
    gingen direkt am Anfang des Jahres los. Im
  • 2:40 - 2:44
    Januar wurden im Firefox und mithin auch
    im tor-Browser, der ja drauf basiert, ein
  • 2:44 - 2:50
    paar Sicherheitslücken geschlossen,
    für die man nur eine Webseite besuchen
  • 2:50 - 2:54
    musste und dann sind da intern irgendwelche
    Buffer Overflows passiert und im
  • 2:54 - 2:58
    schlimmsten Fall konnten Angreifer damit
    halt beliebigen Code ausführen. Ein
  • 2:58 - 3:02
    weiteres Ding aus diesem Jahr, da habe ich
    leider keine schöne Pressemitteilung zu
  • 3:02 - 3:07
    gefunden, nur so einen CVE-Artikel. Der
    Adobe Reader, mal wieder, übrigens guckt
  • 3:07 - 3:13
    mal wie viele Sicherheitslücken der hat,
    das ist enorm. Da war auch was drin mit
  • 3:13 - 3:18
    einem Buffer Overflow und ebenfalls
    arbitrary code execution. Heißt, ein
  • 3:18 - 3:21
    Angreifer kann beliebigen Code auf dem
    Rechner ausführen. Drittes Beispiel, gar
  • 3:21 - 3:26
    nicht so lange her, ist eigentlich im
    letzten Jahr gewesen, und zwar die beiden
  • 3:26 - 3:31
    Würmer Petya und WannaCry. Das waren so
    sympathische Ransomwares, die die
  • 3:31 - 3:36
    Festplatte verschlüsseln und den Besitzer
    dann auffordern, Bitcoins zu überweisen, an
  • 3:36 - 3:40
    eine bestimmte Adresse, damit der Rechner
    wieder frei geschaltet werden kann. Auch
  • 3:40 - 3:46
    die waren beide, also Teil der Angriffe,
    die die genutzt haben, funktionierten über
  • 3:46 - 3:50
    Buffer Overflows. Man sieht also, es ist
    ein Thema mit dem man sehr viel machen
  • 3:50 - 3:55
    kann und deswegen reden wir da jetzt ein
    bisschen darüber. Das ist der grobe
  • 3:55 - 3:58
    Fahrplan, es gibt jetzt so eine kleine
    Vorstellungsrunde, ich sage etwas zu mir,
  • 3:58 - 4:02
    frage was über euch, sag was zum Vortrag.
    Danach machen wir ein paar Grundlagen, die
  • 4:02 - 4:06
    zum Teil sehr technisch und zäh sind, ich
    bitte das zu entschuldigen, aber ganz ohne
  • 4:06 - 4:12
    geht es leider nicht. Und dann erkläre
    ich, wie halt der Exploit funktioniert, so
  • 4:12 - 4:16
    ein Stack Buffer Overflow Exploit und zum
    Schluss gibt es, wenn die Demo-Götter uns
  • 4:16 - 4:20
    weiter gewogen sind, eine Demonstration,
    wo ich meinen eigenen Rechner halt mit
  • 4:20 - 4:29
    einem verwundbaren Programm übernehme.
    Also über mich: Ich bin im Chaos und
  • 4:29 - 4:34
    Hackspace Siegen aktiv und treibe da so
    ein bisschen mein Unwesen, habe so halb
  • 4:34 - 4:38
    den Hut für "Chaos macht Schule" und die
    Cryptoparties auf. Wenn es sich nicht
  • 4:38 - 4:43
    vermeiden lässt, mache ich noch
    Infrastruktur und ähnliche Geschichten. In
  • 4:43 - 4:47
    meinem sonstigen Leben bin ich
    Informatiker, ich programmiere kleine
  • 4:47 - 4:52
    Mikrocontroller für Soundsysteme, ich
    mache Judo und bin Musiker. Meine
  • 4:52 - 4:57
    Lieblingsspeise ist Dal. An dieser stelle
    herzlichen Dank an das Küchenteam, die uns
  • 4:57 - 5:01
    während dem Aufbau sehr gut verpflegt
    haben, unter anderem mit Dal. So, bisschen
  • 5:01 - 5:07
    was über euch. Ein kurzes Funktionscheck:
    Wer hört mir zu und ist in der Lage und
  • 5:07 - 5:13
    gewillt, seinen Arm zu heben bei Fragen,
    die zutreffen? Das sind ungefähr alle,
  • 5:13 - 5:17
    cool. Dann: Wer weiß, wie so ein Rechner
    aufgebaut ist, Stichwort
  • 5:17 - 5:22
    Rechnerarchitektur, Rechenwerk,
    Steuerwerk, so was? Das sind auch
  • 5:22 - 5:27
    erstaunlich viele, okay. Wer hat schon mal
    programmiert? Im Idealfall mit C, das sind
  • 5:27 - 5:34
    ungefähr alle. Wer hat schon mal gehört,
    was ein Stack ist? Was ein Buffer Overflow
  • 5:34 - 5:42
    ist? Wer hat sich bei allem gemeldet? Ihr
    werdet euch langweilen! lacht Der
  • 5:42 - 5:47
    Vortrag ist nämlich, ich habe versucht,
    ihn möglichst einfach zu halten, weil
  • 5:47 - 5:49
    inspiziert inspiriert, entschuldigung,
    inspiriert ist er von einem
  • 5:49 - 5:53
    Arbeitskollegen, den ich eigentlich für
    sehr kompetent halte, und der sich auch
  • 5:53 - 5:57
    auskennt mit Mikrocontrollern, mit
    Assemblycode und der mich irgendwann mal
  • 5:57 - 6:01
    fragte, oder mehr im Nebensatz beiläufig
    erwähnte, dass er nicht verstünde, wie
  • 6:01 - 6:08
    denn eigentlich sein kann, dass ein PDF
    einen Rechner übernehmen kann. Challenge
  • 6:08 - 6:11
    accepted habe ich mir gedacht, das muss
    man doch irgendwie erklären können. Und
  • 6:11 - 6:15
    dann habe ich den Vortrag gemacht, habe
    hier in den Talk eingereicht in Pretalx,
  • 6:15 - 6:19
    der wurde dann halt paar Wochen später
    auch angenommen, dann habe ich mir den
  • 6:19 - 6:21
    Vortrag, den ich zwei Wochen vorher
    zusammengeschraubt hatte, noch einmal
  • 6:21 - 6:25
    angeschaut und geprüft, ob er den
    Anforderungen entspricht, die ich mir
  • 6:25 - 6:29
    selber gesetzt habe, festgestellt oh mein
    Gott, er ist viel zu technisch. Deswegen
  • 6:29 - 6:32
    habe ich den weiter abgespeckt und
    versucht, alle nicht nötigen Details, alle
  • 6:32 - 6:35
    nicht nötigen Fachwörter, alles raus zu
    streichen, was man nicht unbedingt
  • 6:35 - 6:40
    braucht, um das Prinzip eines Stack Buffer
    Overflows oder ein Exploit dessen zu
  • 6:40 - 6:46
    verstehen. Der Vortrag ist vor 20 Minuten
    fertig geworden, ich habe ihn noch nie
  • 6:46 - 6:51
    Probe gehalten, ich habe gestern bei der
    Demo zweimal meinen Rechner abgeschossen,
  • 6:51 - 6:56
    insofern bin ich selber sehr gespannt, was
    jetzt passiert. Also fangen wir an.
  • 6:56 - 7:00
    Grundlagen: Wie funktioniert ein Rechner?
    Wenn man es ganz ganz ganz ganz grob
  • 7:00 - 7:05
    vereinfacht ausdrückt, gibt es irgendwo
    einen Prozessor, da kommen auf der einen
  • 7:05 - 7:12
    Seite Daten rein, nämlich Programmdaten,
    und auf der anderen Seite kommen Daten
  • 7:12 - 7:16
    rein und raus, nämlich die Nutzdaten, die
    ich verarbeiten möchte. Das kann, weiß
  • 7:16 - 7:21
    ich, ein Office-Dokument sein, ein PDF
    oder halt auch Daten aus dem Internet wie
  • 7:21 - 7:28
    HTML-Seiten, bei Web-Browsern sind das halt
    die Daten die rein und raus gehen. Daten
  • 7:28 - 7:35
    werden intern im Rechner in dem Speicher
    abgelegt und zwar in Paketen von acht 1en
  • 7:35 - 7:40
    und 0en. 1en und 0en sind Bits, das wissen
    ja wahrscheinlich alle. So ein Paket von
  • 7:40 - 7:45
    acht davon nennt man ein Byte. Jedes Byte
    hat eine Adresse im Speicher. Und der Witz
  • 7:45 - 7:49
    ist, dass das hier so, dass was da
    gezeichnet ist, nicht ganz korrekt ist,
  • 7:49 - 7:54
    denn Programme und Daten liegen im
    gleichen Speicher. Das heißt, ich kann es
  • 7:54 - 7:58
    theoretisch schaffen, den Prozessor dazu
    zu bringen, Programme auszuführen aus dem
  • 7:58 - 8:02
    Speicherbereich, wo eigentlich Daten
    liegen sollten. Das ist schon eigentlich
  • 8:02 - 8:10
    wie letztendlich so ein Buffer Overflow
    Exploit funktioniert. Wenn ich den
  • 8:10 - 8:14
    Prozessor da in der Mitte doch noch mal
    ein bisschen aufbohre, dann sehe ich, dass
  • 8:14 - 8:19
    er da drin so einen Registersatz hat. Man
    nennt das so, Register. Das ist so ein
  • 8:19 - 8:24
    bisschen vergleichbar mit dem, man könnte
    sagen, das Kurzzeitgedächtnis von
  • 8:24 - 8:29
    Menschen, man sagt Menschen ja nach, sie
    könnten sich so größenordnungsmäßig 7
  • 8:29 - 8:34
    Dinge gleichzeitig merken, kurzzeitig. So
    ähnlich ist das bei einem Prozessor auch,
  • 8:34 - 8:39
    der hat einen sehr begrenzten Satz von
    Registern, also Speicherzellen, die sehr
  • 8:39 - 8:43
    schnell sind, aber halt auch sehr teuer
    sind. Deswegen baut man da nicht so viele
  • 8:43 - 8:46
    von, das sind die Register. Und dann merkt
    er sich halt zum Beispiel, wo er im
  • 8:46 - 8:54
    Programm gerade steht. Also wo im
    Programmspeicher er gerade steht oder wo
  • 8:54 - 8:59
    der Stack gerade steht. Der Stack ist ein
    besonderer Speicherbereich im
  • 8:59 - 9:05
    Datenspeicher, also eigentlich kein
    Programmspeicher, der verwendet wird um
  • 9:05 - 9:10
    Dinge längerfristig abzulegen, also man
    könnte sagen Langzeitgedächtnis. Naja es
  • 9:10 - 9:14
    stimmt nicht ganz, aber grob. Und der
    Stack ist wirklich, der Name ist Programm,
  • 9:14 - 9:18
    ist wie ein Stapel, ich lege unten was
    drauf, dann lege ich was oben drauf, lege
  • 9:18 - 9:21
    etwas weiteres oben drauf, und ich lege
    auch Dinge oder hole Dinge genau in der
  • 9:21 - 9:27
    umgekehrten Reihenfolge wieder runter.
    Also wie ein Stapel Papier eigentlich. Der
  • 9:27 - 9:32
    wird gebraucht, um bestimmte Features von
    Programmiersprachen zu implementieren, das
  • 9:32 - 9:36
    werden wir gleich noch sehen. Wenn jetzt
    also so ein Programm abläuft, also links
  • 9:36 - 9:40
    sieht man einen Ausschnitt aus dem
    Programmspeicher. Also ich habe da jetzt
  • 9:40 - 9:44
    byteweise mal irgendwelche random
    Zahlen hingemalt. Naja es sind keine
  • 9:44 - 9:48
    random Zahlen, es ist tatsächlich ein Teil
    eines Shell-Codes. Also von dem Ding, was
  • 9:48 - 9:52
    ich gleich benutze, um meinen Rechner
    aufzumachen. Die sind jetzt von oben nach
  • 9:52 - 9:56
    unten byteweise aufgelistet und man würde
    jetzt sehen, also Speicheradressen gehen
  • 9:56 - 10:00
    jetzt hier von oben nach unten. Das heißt,
    oben sind die niedrigen Speicheradressen,
  • 10:00 - 10:03
    unten sind die hohen Speicheradressen. Und
    die werden einfach der Reihe nach
  • 10:03 - 10:07
    durchgezählt, jedes Byte hat halt so eine
    Adresse. Und so weiß der Prozessor genau,
  • 10:07 - 10:11
    wenn er gesagt bekommt, macht mal hier an
    der und der Stelle im Programmcode weiter,
  • 10:11 - 10:16
    dann springt er halt dahin und liest
    weiter. Und zwar sieht das so aus, da
  • 10:16 - 10:22
    werden halt Dinge, also dass der Opcode
    oder der Befehl, der gerade ausgeführt
  • 10:22 - 10:25
    werden soll, wird eingelesen und wird
    ausgeführt und der könnte dann zum
  • 10:25 - 10:31
    Beispiel so etwas machen wie ein Datum aus
    dem Registersatz in den Stack legen oder
  • 10:31 - 10:35
    auf den Stack oben drauf legen. Im
    nächsten Schritt wird dann etwas anderes
  • 10:35 - 10:39
    oben draufgelegt und dann wird da wieder
    was runtergeholt und wieder zurück in das
  • 10:39 - 10:42
    Register geschrieben, möglicherweise noch
    irgendwomit verrechnet und so, hangelt er
  • 10:42 - 10:48
    sich halt durch den Code durch. Von oben
    nach unten. Man sieht auch, es muss nicht
  • 10:48 - 10:54
    unbedingt immer alles, jedes Ding muss
    nicht auch ein Befehl sein, da sind auch
  • 10:54 - 10:59
    Daten dazwischen. In diesem Fall halt das,
    was auf den Stack gelegt wurde. Aber im
  • 10:59 - 11:02
    Prinzip funktioniert das so. Ein Rechner
    geht einfach der Reihe nach die Befehle
  • 11:02 - 11:04
    durch. Es gibt dann halt auch
    Sprungbefehle, die sagen können: springe
  • 11:04 - 11:09
    mal irgendwie zurück oder springe mal vor,
    aber im Prinzip ist das alles was ein
  • 11:09 - 11:17
    Rechner macht. Okay, der Shell Code, den
    ich gleich benutzen werde, sieht so aus.
  • 11:17 - 11:22
    Das ist offensichtlich ein Programm, was
    den laufenden Prozess beendet und eine
  • 11:22 - 11:27
    Shell mit dem Namen "sh" startet. Nun ist
    das natürlich nicht so offensichtlich, so
  • 11:27 - 11:30
    will ja keiner Code schreiben. Deswegen
    haben sich Leute einfallen lassen: Hey,
  • 11:30 - 11:34
    wir müssen irgendwie es schaffen, was
    lesbareres zu bekommen und außerdem würden
  • 11:34 - 11:36
    wir ganz gerne, wenn wir ein Programm
    geschrieben haben, das nicht für jeden
  • 11:36 - 11:40
    Prozessor dieser Welt neu schreiben
    müssen. Weil das da ist Code, der nur auf
  • 11:40 - 11:46
    diesem Prozessor, in diesem Fall ein x86
    Prozessor ,läuft. Wenn ich versuche, den
  • 11:46 - 11:49
    auf einem ARM-Prozesor laufen zu lassen,
    dann sagt er: Kenne ich nicht den Befehl,
  • 11:49 - 11:56
    mache ich nicht. Beides erreicht man mit
    sogenannten höheren Programmiersprachen.
  • 11:56 - 12:03
    Eine davon ist C. Das gleiche Programm
    sieht in C so aus. Und hier kann man schon
  • 12:03 - 12:06
    einigermaßen erkennen, okay hier ist
    irgendwie ein String drin, offensichtlich
  • 12:06 - 12:13
    also eine Zeichenkette die auf /bin/sh
    zeigt. Das ist für Leute, die Unix kennen,
  • 12:13 - 12:18
    die Standard Shell. Also ein
    Kommandozeileninterpreter. Und darunter ist
  • 12:18 - 12:23
    eine Zeile, naja die ist wirklich sehr
    kryptisch, die muss man schon kennen. Es
  • 12:23 - 12:26
    ruft halt das Programm auf. Aber wie
    gesagt, Menschen, die sich damit ein
  • 12:26 - 12:30
    bisschen auskennen, die können so etwas
    direkt auf Anhieb lesen, das da oben
  • 12:30 - 12:35
    natürlich nicht. Dieser Code wird jetzt in
    einen sogenannten Compiler reingeschmissen
  • 12:35 - 12:43
    und der Compiler macht dann aus dem
    Unteren ungefähr das Obere wieder. Zudem
  • 12:43 - 12:47
    gibt es dann, wenn man schon so eine
    schöne Abstraktion hat, noch
  • 12:47 - 12:51
    Programmbibliotheken, dass man nicht jeden
    Scheiß neu machen muss. So was wie: öffne
  • 12:51 - 12:55
    mir eine Datei und lies den Inhalt. Das
    will ich ja nicht jedes mal auf der Ebene
  • 12:55 - 13:00
    neu programmieren. Deswegen lege ich mir
    dafür schöne Bibliotheken an, mit
  • 13:00 - 13:05
    Funktionen. Funktionen sind Teile also
    wieder verwertbare Programmteile, die
  • 13:05 - 13:09
    einen definierten Satz von
    Eingabeparametern haben. Also ich kann
  • 13:09 - 13:14
    einer Datei-öffnen-Funktionen
    beispielsweise mitgeben, wo die Datei sich
  • 13:14 - 13:17
    befindet im Dateisystem und ob ich sie
    lesend schreiben (öffnen) möchte oder schreibend
  • 13:17 - 13:23
    oder beides. Dann haben die einen
    Funktionsrumpf. Das ist der Teil der
  • 13:23 - 13:27
    Funktionen, der was macht. Der also das
    tut, was die Funktion tun soll mit den
  • 13:27 - 13:31
    Eingangsparametern und dann gibt es noch
    einen Return-Wert, dass ist also ein
  • 13:31 - 13:34
    Rückgabewert, den die Funktion dann zurück
    gibt, wenn sie fertig ist mit was immer
  • 13:34 - 13:39
    sie getan hat. Und auf diese Weise baut
    man sich halt Bibliotheken und verwendet
  • 13:39 - 13:42
    die halt immer wieder. Dieses execve ganz
    unten ist beispielsweise eine
  • 13:42 - 13:48
    Bibliotheksfunktion. Und das war im
    Prinzip schon alles, was wir für den
  • 13:48 - 14:00
    Exploit wissen müssen. Wenn nämlich jetzt
    so eine Funktionen aufgerufen wird. Nehmen
  • 14:00 - 14:06
    wir mal an, wir hätten eine Funktion, die
    drei Parameter hat, einer davon ist, ach
  • 14:06 - 14:10
    Quatsch. Zwei Parameter hat,
    entschuldigung, und drei lokale Variablen.
  • 14:10 - 14:13
    Achso, Variable habe ich gar nicht
    erklärt. Variablen ist auch ein Konzept
  • 14:13 - 14:18
    von Programmiersprachen. Da kann ich halt
    Speicheradressen sprechende Namen geben.
  • 14:18 - 14:24
    Dass ich halt als Programmierer sehen kann,
    wo ich was abgelegt habe. Und Funktionen
  • 14:24 - 14:29
    können lokale Variablen haben. Davon
    beliebig viele und die werden eben über
  • 14:29 - 14:32
    einen Stack abgebildet, genauso wie die
    Funktionsparameter über einen Stack
  • 14:32 - 14:36
    abgebildet werden und der Rückgabewert
    weiß ich jetzt gerade nicht, da will ich
  • 14:36 - 14:41
    nichts falsches sagen. Könnte sein, dass
    der auch über einen Stack läuft, bin ich
  • 14:41 - 14:45
    mir aber gerade nicht sicher. Nein, ich
    glaube, läuft er nicht, whatever. Wenn ich
  • 14:45 - 14:49
    jetzt mir eine Funktion vorstelle, die
    zwei Parameter hat und drei lokale
  • 14:49 - 14:55
    Variablen. Davon soll eine ein Buffer
    sein, dann passiert, wenn die Funktion
  • 14:55 - 15:00
    aufgerufen wird, folgendes: Zuerst werden
    die Funktionsargumente oder Parameter auf
  • 15:00 - 15:06
    den Stack gelegt, und zwar in umgekehrter
    Reihenfolge. Fragt nicht, ist so. Danach
  • 15:06 - 15:11
    wird die momentane Adresse oder die
    nächste Adresse auf den Stack gelegt,
  • 15:11 - 15:15
    damit das Programm weiß, wenn es aus der
    Funktion zurückkommt, wo es weitermachen
  • 15:15 - 15:21
    muss, weil es folgt ja ein Sprung. Dann
    kommt noch was, das uns nicht interessiert
  • 15:21 - 15:27
    und dann kommen die lokalen Variablen der
    Funktion selber. In diesem Fall eine
  • 15:27 - 15:30
    Variable, dann kommt ein Buffer und dann
    kommt noch eine Variable. An dieser Stelle
  • 15:30 - 15:32
    ist sehr schön zu erklären, was ein
    Buffer ist. Ein Buffer ist
  • 15:32 - 15:39
    eigentlich nichts anderes als eine
    Variable, die aber mehr Speicher hat.
  • 15:39 - 15:44
    Also das ist jetzt nicht eine Zahl,
    sondern es sind beispielsweise 512 Zahlen
  • 15:44 - 15:50
    der gleichen Größe. Das ist ein Buffer.
    Das hier wäre zum Beispiel jetzt ein
  • 15:50 - 15:56
    Buffer der Größe 5. 5 Bytes groß. Die
    können beliebig groß sein, wobei beliebig
  • 15:56 - 16:01
    ist nicht ganz richtig. Hängt von der
    Speichergröße ab, wie ich gestern gelernt
  • 16:01 - 16:08
    habe, bei der Demo. lacht Ja, aber im
    Prinzip sind die nicht begrenzt und das
  • 16:08 - 16:10
    Schlimme ist, man muss sich wenn man so
    low level programmiert, selber darum
  • 16:10 - 16:16
    kümmern, dass man die Grenzen einhält und
    nicht zu viel da rein schreibt. Und dann
  • 16:16 - 16:23
    sind wir schon beim Programm. Das Rechte
    ist das C Program, was ich exploite. Das
  • 16:23 - 16:28
    ist relativ überschaubar, oben diese Zeile
    "int main", das kann man ignorieren, dass
  • 16:28 - 16:33
    braucht man halt, um C zu sagen: hier
    beginnt das Programm, hier geht es los und
  • 16:33 - 16:38
    es ist aber wichtig zu wissen, dass main
    bereits eine Funktion ist. Also vorher
  • 16:38 - 16:44
    passieren noch andere Dinge, die wir nicht
    genauer betrachten, die mir aber sehr
  • 16:44 - 16:49
    viele Steine in den Weg gelegt haben
    gestern. lacht Die rufen am Ende dann
  • 16:49 - 16:55
    halt diese Funktion main auf. Es ist also
    ein ganz normaler Funktionsaufruf. Die
  • 16:55 - 16:58
    Funktion main hat jetzt eine lokale
    Variable, nämlich den Buffer der Größe
  • 16:58 - 17:02
    256. Das ist nicht mehr ganz aktuell, in
    der Demo, die ich gleich zeige, ist er ein
  • 17:02 - 17:08
    bisschen größer, spielt aber keine Rolle.
    Danach gibt es eine Bibliotheksfunktion
  • 17:08 - 17:15
    string copy, strcpy. Die kopiert, was
    immer in argv[1] liegt. Da muss man jetzt
  • 17:15 - 17:20
    dazu sagen, das ist ein
    Kommandozeilenparameter. Wenn ich ein
  • 17:20 - 17:23
    Programm aufrufe auf der Kommandozeile,
    kann ich dem noch Argumente mitgeben und
  • 17:23 - 17:27
    das erste Argument, was ich dem mitgebe in
    diesem Fall, würde halt in den Buffer
  • 17:27 - 17:34
    kopiert. Danach wird eine nette Nachricht
    ausgegeben "Hallo, was immer in dem Buffer
  • 17:34 - 17:39
    steht" und dann folgt das return. Sprich,
    die Funktionen kehrt zurück und dieser
  • 17:39 - 17:43
    ganze Stack wird abgeräumt und der
    Prozessor springt dahin, an die Stelle,
  • 17:43 - 17:48
    deren Adresse jetzt in return links rot
    markiert steht. Also weil vorher hat sich
  • 17:48 - 17:52
    ja das Programm gemerkt, wo es nachher hin
    zurück muss, indem es die Adresse extra da
  • 17:52 - 17:56
    hingelegt hat. Und wenn ich jetzt zu viele
    Daten in diesen Buffer rein schreibe, der
  • 17:56 - 18:01
    ist links verkürzt dargestellt, also
    jetzt die letzten 5 Bytes von diesem 256
  • 18:01 - 18:06
    Bytes Buffer, wenn ich jetzt zu viele
    Daten da reinschreibe, dann kommt
  • 18:06 - 18:10
    irgendwann der Punkt, wo ich halt die
    letzten paar Bytes überschreibe. Dann
  • 18:10 - 18:13
    überschreibe ich das Ding, was uns nicht
    interessiert und irgendwann überschreibe
  • 18:13 - 18:19
    ich die Return-Adresse. Was jetzt
    passiert, erst mal noch nichts. Dann kommt
  • 18:19 - 18:26
    das return 0 und was das return macht: Es
    lädt was immer an dieser stelle steht
  • 18:26 - 18:30
    zurück in den instruction pointer, also an
    die Stelle, wo sich der Prozessor intern
  • 18:30 - 18:35
    merkt, wo das Programm gerade steht und
    macht an der Stelle weiter. Wenn ich es
  • 18:35 - 18:42
    jetzt schaffe, in diesen Buffer meinen
    Shell Code reinzuladen, also das kleine
  • 18:42 - 18:46
    Programmstück, was ihr eben gesehen habt,
    was das laufende Programm beendet und ein
  • 18:46 - 18:49
    neues Programm, nämlich einen
    Kommandozeileninterpreter startet, wenn
  • 18:49 - 18:53
    ich das jetzt schaffe das da oben rein zu
    schreiben und zudem noch es schaffe, an
  • 18:53 - 19:00
    die Return-Adresse den Anfang von diesem
    Code reinzuschreiben, dann passiert genau,
  • 19:00 - 19:04
    was nicht passieren darf: Nämlich das
    Programm macht, was ich ihm vorher gesagt
  • 19:04 - 19:11
    habe und was ich vorher in diesem Buffer
    reingeschrieben habe. Und jetzt kommt der
  • 19:11 - 19:16
    Punkt, an dem es interessant wird. Jetzt
    muss ich erst mal meine Maus wiederfinden,
  • 19:16 - 19:42
    dass habe ich mir alles anders
    vorgestellt. Sieht man das? Das ist ein
  • 19:42 - 19:57
    bisschen klein. Könnt ihr das
    lesen, nein oder? Da hinten, könnt ihr
  • 19:57 - 20:06
    das da hinten lesen? Nein. Bis gerade eben
    konnte ich auch noch die Größe von meinem
  • 20:06 - 20:15
    Terminal verstellen. Das scheint jetzt
    nicht mehr zu gehen. Aha, geht nur auf dem
  • 20:15 - 20:26
    linken Bildschirm, aus Gründen! Könnt ihr
    das jetzt einigermaßen lesen? Gut. Also
  • 20:26 - 20:37
    ich habe hier dieses Programm, ich habe
    das mal vorbereitet. Es macht, was es
  • 20:37 - 20:40
    soll, es liest halt den ersten Parameter
    ein, also "vuln" ist das Programm, das
  • 20:40 - 20:44
    verwundbar ist. Ich habe ihm den Parameter
    "haggl" mit gegeben, also sagt das "Hallo,
  • 20:44 - 20:50
    haggl", alles cool. Wenn ich jetzt aber
    Dinge da rein schreibe, die ein bisschen
  • 20:50 - 21:10
    länger sind, beispielsweise so etwas. Ich
    hoffe, das ist die richtige Syntax um in
  • 21:10 - 21:15
    Python Dinge auf der Kommandozeile direkt
    auszuführen. Ja. Dann kriege ich einen
  • 21:15 - 21:18
    segmentation fault. Ein segmentation fault
    ist der nette Hinweis vom
  • 21:18 - 21:22
    Betriebssystemen: Kollege, du hast gerade
    Speicher lesen und/oder schreiben wollen,
  • 21:22 - 21:30
    auf den du keinen Zugriff hast. Wenn Leute
    die Exploits schreiben, so etwas kriegen,
  • 21:30 - 21:33
    also das ist das was normalerweise das
    kennt wahrscheinlich jeder, was passiert
  • 21:33 - 21:36
    wenn ein Programm einfach so ohne
    irgendetwas zu sagen abstürzt, dann ist
  • 21:36 - 21:41
    das oft ein segmentation fault. Das ist
    für die meisten Menschen sehr nervig, weil
  • 21:41 - 21:43
    man dann das Programm neu starten muss,
    gegebenenfalls Daten verloren gegangen
  • 21:43 - 21:48
    sind. für Leute, die Exploits schreiben,
    ist das der heilige Gral, weil
  • 21:48 - 21:53
    segmentation faults sind oft ein Indiz
    dafür, dass es da gerade einen Buffer
  • 21:53 - 21:56
    Overflow gegeben hat. Und ein Buffer
    Overflow, damit kann man eine Menge
  • 21:56 - 22:11
    anfangen. Man kann beispielsweise einen
    Shell Code reinladen. xxd -p shellcode,
  • 22:11 - 22:16
    das ist das Ding, was wir eben in den
    Slides gesehen haben. Das ist also dieses
  • 22:16 - 22:22
    Programm in Maschinencode, was das
    laufende Programm beendet und eine Shell
  • 22:22 - 22:30
    startet. Und wenn ich die jetzt da rein
    injecte, also anstatt jetzt diesem
  • 22:30 - 22:39
    Pythonding oder dem einfachen String
    haggl, dieses Teil jetzt da rein pipe,
  • 22:39 - 22:44
    dann bekomme ich eine Shell. Und zwar eine
    Shell, die nicht die andere Shell ist,
  • 22:44 - 22:50
    sondern eine neue Shell ist. An der Stelle
    habe ich es geschafft. Jetzt bin ich halt
  • 22:50 - 22:56
    drin und kann hier auf dem System
    beliebige Dinge machen. Das ist erstmal so
  • 22:56 - 23:01
    noch nicht so schlimm und das ist ja auch
    ein sehr akademisches Beispiel, weil ich
  • 23:01 - 23:04
    es alles selber geschrieben habe. Ich muss
    auf dem eigenen Rechner sein, ich bin eh
  • 23:04 - 23:08
    schon der Benutzer, aber interessant wird
    es natürlich, wenn so eine Verwundbarkeit
  • 23:08 - 23:12
    irgendwo an der Stelle sitzt, die auf das
    Netzwerk horcht. Wenn man von außen
  • 23:12 - 23:17
    irgendwie Pakete einschleusen kann, die so
    etwas hervorrufen. Und ich dann irgendwie
  • 23:17 - 23:20
    eine Shell oder ähnliches bekomme. Auch
    interessant wird es, wenn das ein Dienst
  • 23:20 - 23:24
    ist, der aus Gründen mit root-Rechten
    laufen muss. Dann habe ich nämlich auf
  • 23:24 - 23:29
    einmal eine root-Shell. Und so weiter und
    so fort. Also man kann da eine Menge
  • 23:29 - 23:36
    lustige Sachen mit machen. Ich habe noch
    etwas anderes vorbereitet. Und zwar, wenn
  • 23:36 - 23:40
    ich jetzt einen Debugger über das Ding
    laufen lassen. Ein Debugger ist ein
  • 23:40 - 23:45
    Programm, mit dem ich zur Laufzeit rein
    gucken kann, in den Speicher, und schauen
  • 23:45 - 23:49
    kann, was denn der Prozess so gerade da
    macht, und was wo an welcher Stelle im
  • 23:49 - 23:53
    Speicher geschrieben wird. Hier sehe ich
    jetzt noch mal den Quellcode von dem
  • 23:53 - 23:56
    Programm. Das ist das gleiche wie eben,
    bis auf das der Buffer ein bisschen größer
  • 23:56 - 24:04
    ist. Das spielt aber keine große Rolle und
    ich habe zwei breakpoints gesetzt.
  • 24:04 - 24:07
    Breakpoint heißt, das Programm oder der
    Debugger vielmehr, hält das Programm an
  • 24:07 - 24:13
    der Stelle an, damit man halt schauen
    kann, was an bestimmten Speicheradressen
  • 24:13 - 24:18
    steht. Und einer ist hier auf dieser Zeile
    stringcopy, Zeile 6. Also der macht, hält
  • 24:18 - 24:24
    an bevor das reinkopiert wurde, und der
    nächste breakpoint hält kurz vor dem
  • 24:24 - 24:27
    return an. Und da müsste ich halt dann
    schon sehen, was im Buffer passiert ist.
  • 24:27 - 24:32
    Wenn ich das Programm jetzt laufen lasse,
    mit den richtigen Argumenten, das ist
  • 24:32 - 24:36
    alles schon hoffentlich konfiguriert, ja,
    dann sehe ich hier, das es ist ein
  • 24:36 - 24:40
    Ausschnitt aus dem Buffer, und zwar die
    letzten, irgendwo in den letzten paar
  • 24:40 - 24:45
    hundert Bytes, da steht ziemlich
    zufälliger Quatsch drin. Keine Ahnung, was
  • 24:45 - 24:50
    das ist das. Das hat irgend ein Prozess
    vorher, oder vielleicht möglicherweise
  • 24:50 - 24:56
    auch der init Prozess, also das was vor
    meinem eigentlichen main Programm läuft,
  • 24:56 - 25:03
    da hingelegt, keine Ahnung, weiß ich
    nicht. Und die return Adresse steht im
  • 25:03 - 25:07
    Moment noch auf dieser lustigen,
    kryptischen Zahl. Das wird irgendwas sein,
  • 25:07 - 25:12
    was, nachdem main beendet wurde, also die
    Funktion main beendet wurde,
  • 25:12 - 25:18
    wahrscheinlich noch irgendwie Speicher
    aufräumt oder so etwas. So, jetzt sind wir
  • 25:18 - 25:22
    also an der Stelle stringcopy, also es ist
    noch nichts passiert. Wenn ich jetzt zum
  • 25:22 - 25:31
    nächsten breakpoint weiterlaufe, dann seht
    ihr? Hier oben sind ganz viele 0x90
  • 25:31 - 25:35
    Instruktionen. Das sind die Anweisungen
    für den Prozessor: mach mal nichts, warte
  • 25:35 - 25:40
    mal einen Takt lang. Und davon habe ich
    ganz viele da rein geschrieben und
  • 25:40 - 25:45
    irgendwann kommt dann hier dieser Shell
    Code. Das war das Ding, was eben das
  • 25:45 - 25:51
    Programm beendet und die Shell startet.
    Und ich kann auch schon sehen, die return
  • 25:51 - 25:54
    Adresse ist jetzt überschrieben worden mit
    einer Adresse, die ich selber gewählt
  • 25:54 - 25:59
    habe. Und diese Adresse, die zielt
    irgendwo oben vor den Shell Code in diese
  • 25:59 - 26:05
    ganzen no-operation Instruktionen, das
    nennt man eine NOP-slide. Das macht man,
  • 26:05 - 26:07
    um ein bisschen zu puffern und ein
    bisschen Platz zu haben und ein bisschen
  • 26:07 - 26:11
    Freiheit zu haben, weil wenn so ein
    Prozess gestartet wird, dann hängen da
  • 26:11 - 26:16
    oben über dem Stack noch ganz viele andere
    Sachen und die können sich, nicht zur
  • 26:16 - 26:19
    Laufzeit, die können sich aber auch von
    Programmausführung zu Programmausführung
  • 26:19 - 26:24
    ändern. Wenn ich zum Beispiel eine neue
    Variable definiere oder whatever.
  • 26:24 - 26:27
    Jedenfalls habe ich die Sachen nicht immer
    exakt an der gleichen Speicheradresse und
  • 26:27 - 26:29
    deswegen macht man gerne so einen NOP-
    slide. Also man nimmt seinen Shell Code,
  • 26:29 - 26:33
    packt den irgendwo in die Mitte, packt
    davor ganz viele NOPs, wo der Rechner
  • 26:33 - 26:35
    einfach so durchtingelt und nichts tut,
    und dann irgendwann an dem Shell Code
  • 26:35 - 26:39
    ankommt und dahinter packt man ganz viele
    return Adressen, die oben in diese NOP-
  • 26:39 - 26:45
    Slide reinspringen. Das heißt, egal ob ich
    den Bereich vor dem Shell Code treffe oder
  • 26:45 - 26:48
    den Bereich hinter dem Shell Code treffe,
    es passiert immer was passieren muss,
  • 26:48 - 26:52
    nämlich er springt im ungünstigsten Fall
    von hinterm Shell Code zu vor dem Shell
  • 26:52 - 26:56
    Code und hangelt sich dann durch bis zum
    Shell Code, der dann das tut, was er tut.
  • 26:56 - 27:09
    Und das ist der Buffer Overflow Exploit.
    Demo Time! Ja wobei, wie ich schon sagte,
  • 27:09 - 27:13
    das ist ein sehr akademisches Beispiel,
    weil ich das alles halt sehr, um es
  • 27:13 - 27:19
    einfach zu halten, sehr klein gehalten
    habe. In der Realität würde man sagen, es
  • 27:19 - 27:22
    ist ja keiner so blöd, wenn da irgendwas
    in den Puffer rein schreibt, nicht zu
  • 27:22 - 27:25
    checken, wie groß denn der Puffer ist und
    mal zu gucken, ob man überhaupt noch da
  • 27:25 - 27:34
    rein schreiben darf. Das stimmt auch,
    meistens. lacht Das Problem ist: selbst,
  • 27:34 - 27:38
    wenn es immer gemacht würde, habe ich oft
    das Problem, dass ich das zu der Zeit, wo
  • 27:38 - 27:41
    ich das Programm schreibe, noch gar nicht
    wissen kann, wie groß dieser Buffer sein
  • 27:41 - 27:44
    muss, weil ich es erst zur Laufzeit
    mitbekomme, wie viele Pakete da jetzt
  • 27:44 - 27:48
    gleich ankommen, wenn es zum Beispiel ein
    Netzwerkdienst ist. Das heißt, die Größe
  • 27:48 - 27:51
    von so einem Buffer wird oft berechnet und
    wenn ich jetzt bei der Berechnung der
  • 27:51 - 27:54
    Größe irgend einen Fehler habe, der dazu
    führt, dass ich eine falsche Größe raus
  • 27:54 - 27:58
    bekomme, die dann dazu führt, dass der
    Rechner, oder das Programm vielmehr,
  • 27:58 - 28:03
    denkt, der Buffer ist riesig groß, dann
    schreibt das Ding halt weiter. Das ist
  • 28:03 - 28:12
    eine Sache, die oft ausgenutzt wird und
    Daten kommen halt eben, let's face it,
  • 28:12 - 28:18
    meistens nicht von der Kommandozeile, aber
    stattdessen kommen die aus Dateien, die
  • 28:18 - 28:23
    ich irgendwie manipulieren kann oder sogar
    aus dem Netzwerk. Da habe ich natürlich
  • 28:23 - 28:28
    dann beliebige Angriffsvektoren. Das
    heißt, was in der Realität passieren
  • 28:28 - 28:33
    würde, also jetzt beispielsweise bei
    diesen drei Dingern die wir da hatten: Das
  • 28:33 - 28:40
    Erste war ja der Firefox Browser. Da würde
    man vermutlich ein Bild beispielsweise
  • 28:40 - 28:45
    sich zusammen bauen, was irgendwie den
    Bild Standard nicht ganz erfüllt oder wo
  • 28:45 - 28:53
    irgendwo ein Byte falsch ist, so dass, wenn
    der Browser das Bild lädt, sich irgendwo
  • 28:53 - 28:57
    verhaspelt und irgendwo es zu einem Buffer
    Overflow kommt, weil z. B. ein Puffer zu
  • 28:57 - 29:03
    klein ausgelegt wird. Oder ich kann
    versuchen, es über Javascript Dinge zu
  • 29:03 - 29:08
    machen, aber das ist eigentlich noch was
    anderes. Im zweiten Fall, von dem Adobe
  • 29:08 - 29:13
    Reader, sind es auch oft tatsächlich
    irgendwelche Bilder. Das Problem bei dem
  • 29:13 - 29:16
    Adobe Reader ist halt so ein bisschen das
    der so eine eierlegende Wollmilchsau ist.
  • 29:16 - 29:22
    Ich kann mit dem Teil ja beliebige
    Bildformate anzeigen lassen, Text mit
  • 29:22 - 29:26
    eigenen Schriften, dass wäre auch ein
    Angriffsvektor, wenn ich da eine eigene
  • 29:26 - 29:29
    Schrift einbauen und die Schrift halt
    irgendwie so baue, dass beim Einlesen und
  • 29:29 - 29:34
    beim Parsen und Bauen dieser Schrift der
    Reader irgendwie einen Buffer Overflow
  • 29:34 - 29:40
    kriegt. Bis hin zu 3D Elemente, ich habe
    gehört, sie haben teile von Flash in den
  • 29:40 - 29:45
    Adobe Reader eingebaut, damit man damit
    dann 3D Modelle irgendwie anzeigen und
  • 29:45 - 29:50
    auch schön drehen kann. Was man ja alles
    braucht, alles im gleichen Programm, gute
  • 29:50 - 29:55
    Idee! Naja jedenfalls, auch da bieten sich
    verschiedenste Angriffsvektoren und was
  • 29:55 - 30:01
    man machen würde ist halt eine Datei
    bauen, die halten den Fehler ausnutzt und
  • 30:01 - 30:08
    einen Buffer Overflow erzeugt. Der Angriff
    den ich hier gezeigt habe, der ist heute
  • 30:08 - 30:12
    aus verschiedenen Gründen nicht mehr
    möglich. Ich musste drei Dinge abschalten
  • 30:12 - 30:16
    um den überhaupt laufen lassen zu können.
    Das Eine ist, wie ihr euch wahrscheinlich
  • 30:16 - 30:19
    jetzt schon gedacht habt, naja dann könnte
    ich doch einfach sagen ich habe einen
  • 30:19 - 30:23
    bestimmten Programmspeicher, ich habe
    einen bestimmten Datenspeicher und was im
  • 30:23 - 30:26
    Datenspeicher liegt, darf niemals nicht vom
    Prozessor ausgeführt werden. Das gibt es.
  • 30:26 - 30:32
    Das nennt sich "write XOR execute" und ist
    seit einigen Jahren im Kernel und sogar in
  • 30:32 - 30:37
    Hardware drin. Wenn es angeschaltet ist.
    Das musste ich ausschalten, dann gibt es
  • 30:37 - 30:42
    noch die Möglichkeit sogenannte Stack
    Canaries, also Kanarienvögel, in den Stack
  • 30:42 - 30:47
    einzubauen. Das ist so ein Magic Byte, was
    da reingeschrieben wird, und ein bisschen
  • 30:47 - 30:51
    Code, was vor dem rückkehren der Funktion
    noch einmal testet, ob dieses Byte, was
  • 30:51 - 30:57
    ich da reingeschrieben habe, also zwischen
    den lokalen Variablen und der
  • 30:57 - 31:01
    Returnadresse, moment ich mache das mal
    eben grafisch, damit man das sehen kann,
  • 31:01 - 31:05
    genau, also an diese Stelle, die jetzt da
    schwarz markiert ist, zwischen dem Return
  • 31:05 - 31:10
    und dem Buffer, würde man ein zur Laufzeit
    gewähltes beliebiges Byte reinschreiben
  • 31:10 - 31:14
    und bevor man aus der Funktion
    zurückkehrt, würde man testen, ob dieses
  • 31:14 - 31:19
    Byte, was man da vorher reingeschrieben
    hat, noch das gleiche ist wie vorher. Wenn
  • 31:19 - 31:21
    nicht, ist ein Buffer Overflow passiert
    und dann lässt man das Programm besser
  • 31:21 - 31:26
    sofort abstürzen, anstatt abzuwarten, was
    jetzt kommt. Das ist ein Stack Canary.
  • 31:26 - 31:33
    Auch das musste ich ausschalten. Und das
    Dritte ist bei modernen Betriebssystemen,
  • 31:33 - 31:36
    mittlerweile haben es glaube ich alle
    drin, ist das so, dass jeder Prozess mit
  • 31:36 - 31:43
    einem zufälligen Speicherlayout läuft. Das
    heißt, ich kann nicht mehr wirklich sagen
  • 31:43 - 31:46
    wo meine Dinge im Speicher liegen und das
    macht es sehr sehr schwierig, weil ich ja
  • 31:46 - 31:52
    irgendwo an den Shell Code, an das Ende
    vom Shell Code, eine Adresse schreiben
  • 31:52 - 31:56
    muss, die vorne in diese NOP slide
    reinführt. Und wenn ich absolut keine
  • 31:56 - 31:59
    Ahnung habe, wo diese Adresse ist, also
    ich kann nicht mehr durch Vergrößern des
  • 31:59 - 32:02
    Buffers oder durch mehr NOPs einfügen kann
    ich das irgendwann nicht mehr schaffen,
  • 32:02 - 32:06
    weil es einfach so zufällig ist, dass ich
    keine Chance mehr habe herauszufinden, wo
  • 32:06 - 32:11
    zur Laufzeit denn dieser Shell Code liegt,
    und wenn ich nicht weiß wo der liegt, kann
  • 32:11 - 32:15
    ich da nicht rein springen, kann ich also
    keinen Buffer Overflow Exploit machen.
  • 32:15 - 32:19
    Diese drei Dinge gibt es heute, die sind
    in der Regel, also zwei davon macht der
  • 32:19 - 32:23
    Compiler, das Dritte macht das
    Betriebssystem, und die musste ich jetzt
  • 32:23 - 32:27
    alle umgehen, um das überhaupt
    demonstrieren zu können. Aber die zugrunde
  • 32:27 - 32:32
    liegenden Probleme bestehen weiterhin, die
    sind nämlich: Speichermanagement ist
  • 32:32 - 32:37
    fehleranfällig, Menschen machen immer
    Fehler, ist oft auch nicht so
  • 32:37 - 32:41
    übersichtlich, Datenformate sind zu
    komplex, Programme müssen zu viel
  • 32:41 - 32:46
    gleichzeitig können und das führt alles
    dazu, dass halt immer mehr Fehler
  • 32:46 - 32:49
    passieren. Je höher die Komplexität ist,
    desto höher ist natürlich die
  • 32:49 - 32:54
    Wahrscheinlichkeit, das ich Fehler mache.
    Und das ist nicht gefixt und die
  • 32:54 - 32:58
    Programmiersprachen, die man dafür
    verwendet, sind eigentlich einer Zeit
  • 32:58 - 33:04
    entstammend, in der das Internet noch ein
    freundlicher Ort war. Man kannte sich und
  • 33:04 - 33:09
    da hat man über Security nicht so richtig
    nachgedacht. Es gibt außerdem Nachfolger
  • 33:09 - 33:13
    von dieser Praxis, also diese Praxis, die
    ich jetzt hier gezeigt habe, geht halt
  • 33:13 - 33:17
    nicht, aber es gibt Nachfolger davon, also
    Modifikationen davon, die sind ein
  • 33:17 - 33:20
    bisschen gewiefter, ein bisschen
    trickreicher und die schaffen es dann,
  • 33:20 - 33:24
    unter Umständen eben doch noch so etwas
    nicht zu bekommen. Also das funktioniert
  • 33:24 - 33:30
    heute immer noch, wie ihr halt an den
    Nachrichten gesehen habt. Oft werden auch
  • 33:30 - 33:38
    nicht alle Gegenmaßnahmen ergriffen, das
    ist halt Teil der Betriebssystemhersteller
  • 33:38 - 33:44
    bzw. Benutzer. An der Stelle danke ich und
    Fragen?
  • 33:44 - 33:53
    Applaus
  • 33:53 - 34:02
    Herald: Herzlichen Dank haggl für diesen
    wundervollen Vortrag! So, Frage-Antwort-
  • 34:02 - 34:08
    Runde, es gibt zwei Mikrofone, die sind
    dort und dort, beleuchtet, wer eine Frage
  • 34:08 - 34:15
    hat, stellt sich bitte hinter die
    Mikrofone und ich rufe dann auf. Keine
  • 34:15 - 34:25
    Fragen? Das scheint ein ganz schön
    umfangreicher Vortrag gewesen zu sein.
  • 34:25 - 34:30
    Haggl: Keine Fragen, oder seid ihr
    bedient? Keine Fragen, weil es zu viele
  • 34:30 - 34:38
    gäbe, oder keine Fragen, weil es gar keine
    mehr gibt? Achso, eine Entweder-Oder-Frage
  • 34:38 - 34:42
    kann man nicht mit Handzeichen
    beantworten, das ist schwierig. lacht
  • 34:42 - 34:46
    Herald: Dort steht jemand, bitte.
    Frage: Ich hätte mal eine Frage und zwar:
  • 34:46 - 34:51
    Ich habe die Stelle nicht gefunden, wo die
    Return-Adresse ausgerechnet wird und
  • 34:51 - 34:54
    reingeschrieben wird, also der Return-
    Wert.
  • 34:54 - 34:57
    Haggl: Ja, die konntest du auch nicht
    finden, weil ich die garnicht gezeigt
  • 34:57 - 35:17
    habe. Ich habe dazu noch ein kleines
    Pythonskript, das das alles macht. Das ist
  • 35:17 - 35:21
    diese hier. Also der der Shellcode, den
    ich vorher gezeigt habe, das ist wirklich
  • 35:21 - 35:29
    nur der Part, der halt execve aufruft mit
    /bin/sh und der wird halt hier eingelesen
  • 35:29 - 35:33
    in diesem Pythonskript und dann baue ich
    mit dem Pythonskript halt eben ganz viele
  • 35:33 - 35:37
    NOPs davor, das ist an der Stelle, also
    hier berechne ich erstmal wie lange diese
  • 35:37 - 35:41
    NOP-slide sein soll und packe halt
    den NOP-slide davor, dann kommt noch ein
  • 35:41 - 35:45
    bisschen Padding und Alignment, damit
    das alles richtig hinten rauskommt, dass
  • 35:45 - 35:51
    die Rücksprungadresse auch an der
    richtigen Stelle liegt im stack. Genau und
  • 35:51 - 35:56
    hier oben habe ich halt diese Target-
    Adresse und die kriegst du halt nur raus,
  • 35:56 - 35:58
    wenn du das Programm einmal laufen lässt
    und mit dem Debugger schaust, na wo ist
  • 35:58 - 36:02
    denn der Buffer. Und dann kannst du halt
    irgendwie eine Adresse in der Mitte von
  • 36:02 - 36:08
    dem Buffer aussuchen, den Shellcode
    dahinter packen, ein par NOPs davor, dann
  • 36:08 - 36:14
    tut es das schon. So weit die Theorie, die
    Praxis, habe ich schmerzhaft gelernt, ist
  • 36:14 - 36:19
    ein bisschen komplizierter. Genau, also
    mehr macht dieses Skript auch nicht, es
  • 36:19 - 36:21
    nimmt den Shellcode, packt NOPs davor,
    return-Adresse dahinter, fertig.
  • 36:21 - 36:26
    Frage: Ist die Adresse eine relative oder
    eine absolute Adresse?
  • 36:26 - 36:33
    Haggl: Das ist eine absolute Adresse. Und
    das ist halt das Ding, an der Stelle
  • 36:33 - 36:37
    greift halt dieses address space layout
    randomization, also dieser
  • 36:37 - 36:40
    Abwehrmechanismus vom Betriebssystem, der
    dafür sorgt, dass jedes mal, wenn ich das
  • 36:40 - 36:45
    Programm aufrufe, diese Adresse nicht mehr
    stimmt. Das kann ich euch demonstrieren.
  • 36:45 - 37:02
    Wenn ich jetzt dieses Ding, was nämlich
    der make Befehl macht, weil, wenn ich
  • 37:02 - 37:06
    dieses make exploit mache, was ich euch
    eben gezeigt habe, da wird vorher noch mit
  • 37:06 - 37:12
    diesem Befehl hier für den nächsten
    Prozess, dieses address space layout
  • 37:12 - 37:17
    randomization ausgeschaltet. Standardmäßig
    ist das an im Linux Kernel und wenn ich
  • 37:17 - 37:23
    das nicht mache, sondern einfach nur das
    Programm aufrufe und da meine payload
  • 37:23 - 37:32
    reinschiebe, dann gibt es zwar auch einen
    segmentation fault, natürlich, aber es
  • 37:32 - 37:38
    gibt halt, ich kriege halt keine shell.
    Und das ist genau aus dem Grund, weil der
  • 37:38 - 37:42
    buffer nicht an der Stelle liegt, wo ich
    ihn vermutet habe und deswegen meine
  • 37:42 - 37:46
    Rücksprungadresse irgendwo im Speicher
    zeigt, da springt er dann hin und, ups,
  • 37:46 - 37:54
    gibts einen segmentation fault. Die beiden
    anderen Dinge könnte ich auch noch eben
  • 37:54 - 37:59
    zeigen, ich weiß nicht, wir haben noch
    Zeit oder? Die beiden an Dinge könnte ich
  • 37:59 - 38:03
    eben auch noch zeigen, also was man machen
    muss, um die beiden anderen
  • 38:03 - 38:07
    Sicherheitsmechanismen abzuschalten. Da
    muss man das Programm nämlich mit diesen
  • 38:07 - 38:18
    beiden "-z execstack", das ist dieses was
    den Softwarecheck ausschaltet, ob ich
  • 38:18 - 38:23
    gerade im stack versuche Programme, also
    generell im Datenspeicher, nein im stack,
  • 38:23 - 38:28
    versuche, Programme auszuführen. Das muss
    man ausschalten. Und dann gibt es noch
  • 38:28 - 38:32
    diesen stack protector, dass ist ein stack
    canarie, dass wird auch standardmäßig
  • 38:32 - 38:38
    eingebaut. Muss man also auch explizit
    ausschalten, um das möglich zu machen. Das
  • 38:38 - 38:41
    heißt , Programme, die mit modernen
    compilern und modernen compiler flags
  • 38:41 - 38:46
    kompiliert wurden, sollten trade mark
    eigentlich nicht so leicht verwundbar
  • 38:46 - 38:50
    sein. Und wenn dann noch address space
    layout randomization dazu kommt, dann ist
  • 38:50 - 38:55
    das schon relativ gut, da muss man schon
    echt eine Menge Zeug machen, um dann noch
  • 38:55 - 39:02
    irgendwie reinzukommen. Aber es geht halt
    trotzdem.
  • 39:02 - 39:06
    Herald: Gut ich sehe da drüben an dem
    Mikrofon noch jemanden, der wartet, bitte.
  • 39:06 - 39:12
    Frage: Kann man nicht einfach relative
    Adressen verwenden, um ASLR auszuhebeln
  • 39:12 - 39:17
    und wenn nein, warum nicht?
    Haggl: Was meinst du mit relativ, relativ
  • 39:17 - 39:23
    wozu?
    Frage: Naja, also ich meine, ah nein, ich
  • 39:23 - 39:30
    habe es gerafft, okay.
    Haggl: Aber im Prinzip bist du auf dem
  • 39:30 - 39:36
    richtigen Weg, also was man halt machen
    kann, ist, man kann herausfinden, wo die
  • 39:36 - 39:41
    libc zum Beispiel anfängt. Und wenn ich
    weiß, wo die libc anfängt, dann weiß ich
  • 39:41 - 39:45
    auch, wenn ich zudem noch die Version von
    der libc kenne, die da reingelinkt wurde,
  • 39:45 - 39:50
    weiß ich dann auch, wo bestimmte Dinge aus
    der libc im Speicher liegen. Und sobald
  • 39:50 - 39:55
    ich das habe, kann ich halt dann anfangen,
    mir wieder Dinge zusammenzubauen. Das geht
  • 39:55 - 39:57
    aber dann eher in Richtung return oriented
    programming.
  • 39:57 - 40:07
    Herald: Gut, sieht aus, als sei die Frage
    beantwortet, gibt es noch weitere Fragen?
  • 40:07 - 40:11
    Das scheint nicht der Fall zu sein, aus
    dem Internet scheint auch keine Frage zu
  • 40:11 - 40:21
    kommen. Dann würde ich hiermit den Vortrag
    schließen, herzlichen Dank haggl!
  • 40:21 - 40:27
    Applaus
  • 40:27 - 40:33
    35c3 Abspannmusik
  • 40:33 - 40:47
    Untertitel erstellt von c3subtitles.de
    im Jahr 2020. Mach mit und hilf uns!
Title:
35C3 ChaosWest - Stack Buffer Overflow Exploits - Wie ein "harmloses" Dokument einen Rechner infizi
Description:

more » « less
Video Language:
German
Duration:
40:47

German subtitles

Revisions