Ret2esp / Ret2reg
Ret2esp
Da der ESP (Stack-Zeiger) immer auf den obersten Teil des Stacks zeigt, beinhaltet diese Technik das Ersetzen des EIP (Instruktionszeigers) 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 aktivem ASLR könnte es jedoch erforderlich sein, innerhalb des anfälligen Programms selbst nach diesen Anweisungen zu suchen (und Sie müssen möglicherweise PIE umgehen).
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:
Sie können ein weiteres Beispiel für diese Technik unter https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html sehen. Es handelt sich um einen Buffer Overflow ohne NX-Unterstützung, bei dem ein Gadget verwendet wird, um die Adresse von $esp
zu verringern, gefolgt von einem 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
Einige Beispiele findest du hier:
strcpy
wird die Adresse des Buffers, in dem der Shellcode gespeichert ist, 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 Buffer Overflow und vom Benutzer kontrolliert) in x0
gespeichert ist, bevor aus dem Buffer Overflow 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är ohne PIE kompiliert ist. Durch Verwendung eines Musters ist es möglich zu sehen, dass der Offset des Buffer Overflows 80 beträgt, daher wäre der Exploit:
Wenn anstelle von fgets
etwas wie read
verwendet worden wäre, wäre es auch möglich gewesen, PIE zu umgehen, indem nur die letzten 2 Bytes der Rücksprungadresse überschrieben werden, um zur br x0;
Anweisung zurückzukehren, ohne die vollständige Adresse zu kennen.
Mit fgets
funktioniert das 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