Ret2esp / Ret2reg
Ret2esp
Da der ESP (Stack Pointer) immer auf den obersten Teil des Stacks zeigt, beinhaltet diese Technik das Ersetzen des EIP (Instruction Pointer) durch die Adresse einer jmp esp
oder call esp
Anweisung. Dadurch wird der Shellcode direkt nach dem überschriebenen EIP platziert. Wenn die ret
-Anweisung ausgeführt wird, zeigt ESP auf die nächste Adresse, genau dort, wo der Shellcode gespeichert ist.
Wenn Address Space Layout Randomization (ASLR) in Windows oder Linux nicht aktiviert ist, ist es möglich, jmp esp
oder call esp
Anweisungen in gemeinsam genutzten Bibliotheken zu verwenden. Mit ASLR aktiviert, muss man möglicherweise innerhalb des anfälligen Programms selbst nach diesen Anweisungen suchen (und man muss PIE überwinden).
Darüber hinaus ermöglicht es, den Shellcode nach der EIP-Korruption zu platzieren, anstatt in der Mitte des Stacks, sicherzustellen, dass keine push
oder pop
Anweisungen, die während des Betriebs der Funktion ausgeführt werden, den Shellcode beeinträchtigen. Diese Beeinträchtigung könnte auftreten, wenn der Shellcode in der Mitte des Stacks der Funktion platziert wäre.
Platzmangel
Wenn Ihnen der Platz zum Schreiben nach dem Überschreiben von RIP fehlt (vielleicht nur wenige Bytes), schreiben Sie einen anfänglichen jmp
Shellcode wie:
Und schreiben Sie den Shellcode früh im Stapel.
Beispiel
Sie können ein Beispiel für diese Technik unter https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp finden mit einem endgültigen Exploit wie:
Du kannst ein weiteres Beispiel dieser Technik in https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html sehen. Es handelt sich um einen Buffer Overflow ohne NX aktiviert, es wird ein Gadget verwendet, um die Adresse von $esp
zu verringern und dann ein jmp esp;
um zum Shellcode zu springen:
Ret2reg
Ebenso können wir, wenn wir wissen, dass eine Funktion die Adresse zurückgibt, an der der Shellcode gespeichert ist, die call eax
- oder jmp eax
-Anweisungen nutzen (bekannt als ret2eax-Technik), um eine weitere Methode zum Ausführen unseres Shellcodes zu bieten. Genau wie eax könnte jeder andere Registerwert mit einer interessanten Adresse verwendet werden (ret2reg).
Beispiel
Hier finden Sie einige Beispiele:
strcpy
wird die Adresse des Puffers, in dem der Shellcode gespeichert war, ineax
speichern undeax
wird nicht überschrieben, daher ist es möglich, einret2eax
zu verwenden.
ARM64
Ret2sp
In ARM64 gibt es keine Anweisungen, die es ermöglichen, zum SP-Register zu springen. Es könnte möglich sein, ein Gadget zu finden, das sp in ein Register verschiebt und dann zu diesem Register springt, aber in der libc meines Kali konnte ich kein solches Gadget finden:
Die einzigen, die ich entdeckt habe, würden den Wert des Registers ändern, in dem sp kopiert wurde, bevor darauf gesprungen wurde (so würde es nutzlos werden):
Ret2reg
Wenn ein Register eine interessante Adresse hat, ist es möglich, einfach zu dieser zu springen, indem man die geeignete Anweisung findet. Man könnte etwas Ähnliches verwenden:
In ARM64 speichert x0
den Rückgabewert einer Funktion, daher könnte es sein, dass x0 die Adresse eines vom Benutzer kontrollierten Puffers speichert, der einen Shellcode zum Ausführen enthält.
Beispielcode:
Beim Überprüfen der Disassembly der Funktion ist es möglich zu sehen, dass die Adresse des Buffers (anfällig für Pufferüberläufe und vom Benutzer kontrolliert) in x0
gespeichert ist, bevor aus dem Pufferüberlauf zurückgekehrt wird:
Es ist auch möglich, das Gadget br x0
in der Funktion do_stuff
zu finden:
Wir werden dieses Gadget verwenden, um dorthin zu springen, da das Binärprogramm OHNE PIE kompiliert ist. Durch Verwendung eines Musters ist es möglich zu sehen, dass der Offset des Pufferüberlaufs 80 beträgt, daher wäre der Exploit:
Wenn anstelle von fgets
etwas wie read
verwendet worden wäre, wäre es möglich gewesen, PIE auch nur durch Überschreiben der letzten 2 Bytes der Rücksprungadresse zu umgehen, um zur br x0;
Anweisung zurückzukehren, ohne die vollständige Adresse zu kennen.
Mit fgets
funktioniert es nicht, weil es ein Nullbyte (0x00) am Ende hinzufügt.
Schutzmaßnahmen
NX: Wenn der Stack nicht ausführbar ist, hilft dies nicht, da wir den Shellcode auf dem Stack platzieren und zu seiner Ausführung springen müssen.
Referenzen
Last updated